diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index ce475773d..b096455ad 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -73,9 +73,11 @@ bool GPU::DoState(StateWrapper& sw) sw.Do(&m_render_state.texture_y_flip); sw.Do(&m_render_state.texpage_attribute); sw.Do(&m_render_state.texlut_attribute); + sw.Do(&m_render_state.texture_window_value); sw.Do(&m_render_state.texture_page_changed); sw.Do(&m_render_state.texture_color_mode_changed); sw.Do(&m_render_state.transparency_mode_changed); + sw.Do(&m_render_state.texture_window_changed); sw.Do(&m_drawing_area.left); sw.Do(&m_drawing_area.top); @@ -113,6 +115,7 @@ bool GPU::DoState(StateWrapper& sw) m_render_state.texture_page_changed = true; m_render_state.texture_color_mode_changed = true; m_render_state.transparency_mode_changed = true; + m_render_state.texture_window_changed = true; UpdateGPUSTAT(); } @@ -437,10 +440,7 @@ void GPU::WriteGP0(u32 value) case 0xE2: // set texture window { - m_render_state.texture_window_mask_x = param & UINT32_C(0x1F); - m_render_state.texture_window_mask_y = (param >> 5) & UINT32_C(0x1F); - m_render_state.texture_window_offset_x = (param >> 10) & UINT32_C(0x1F); - m_render_state.texture_window_offset_y = (param >> 15) & UINT32_C(0x1F); + m_render_state.SetTextureWindow(value); Log_DebugPrintf("Set texture window %02X %02X %02X %02X", m_render_state.texture_window_mask_x, m_render_state.texture_window_mask_y, m_render_state.texture_window_offset_x, m_render_state.texture_window_offset_y); @@ -895,6 +895,20 @@ void GPU::RenderState::SetFromPaletteAttribute(u16 value) texture_page_changed = true; } +void GPU::RenderState::SetTextureWindow(u32 value) +{ + value &= TEXTURE_WINDOW_MASK; + if (texture_window_value == value) + return; + + texture_window_mask_x = value & UINT32_C(0x1F); + texture_window_mask_y = (value >> 5) & UINT32_C(0x1F); + texture_window_offset_x = (value >> 10) & UINT32_C(0x1F); + texture_window_offset_y = (value >> 15) & UINT32_C(0x1F); + texture_window_value = value; + texture_window_changed = true; +} + bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha) { std::vector rgba8_buf(width * height); diff --git a/src/core/gpu.h b/src/core/gpu.h index 137f5bb8e..ebd43c9e3 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -240,6 +240,7 @@ protected: static constexpr u16 PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK = UINT16_C(0b0000000000011111); static constexpr u16 PAGE_ATTRIBUTE_MASK = UINT16_C(0b0000000111111111); static constexpr u16 PALETTE_ATTRIBUTE_MASK = UINT16_C(0b0111111111111111); + static constexpr u32 TEXTURE_WINDOW_MASK = UINT16_C(0b11111111111111111111); // decoded values u32 texture_page_x; @@ -258,10 +259,12 @@ protected: // original values u16 texpage_attribute; // from register in rectangle modes/vertex in polygon modes u16 texlut_attribute; // from vertex + u32 texture_window_value; bool texture_page_changed = false; bool texture_color_mode_changed = false; bool transparency_mode_changed = false; + bool texture_window_changed = false; bool IsChanged() const { return texture_page_changed || texture_color_mode_changed || transparency_mode_changed; } @@ -274,11 +277,15 @@ protected: bool IsTransparencyModeChanged() const { return transparency_mode_changed; } void ClearTransparencyModeChangedFlag() { transparency_mode_changed = false; } + bool IsTextureWindowChanged() const { return texture_window_changed; } + void ClearTextureWindowChangedFlag() { texture_window_changed = false; } + void SetFromPolygonTexcoord(u32 texcoord0, u32 texcoord1); void SetFromRectangleTexcoord(u32 texcoord); void SetFromPageAttribute(u16 value); void SetFromPaletteAttribute(u16 value); + void SetTextureWindow(u32 value); } m_render_state = {}; struct DrawingArea diff --git a/src/core/gpu_hw.cpp b/src/core/gpu_hw.cpp index 5852946f9..33d577bc7 100644 --- a/src/core/gpu_hw.cpp +++ b/src/core/gpu_hw.cpp @@ -46,9 +46,17 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices) hw_vert.texpage = texpage; if (textured) + { hw_vert.texcoord = Truncate16(m_GP0_command[buffer_pos++]); + // auto [u, v] = HWVertex::DecodeTexcoord(hw_vert.texcoord); + // u = (u & (~(m_render_state.texture_window_mask_x * 8))) | ((m_render_state.texture_window_offset_x & + // m_render_state.texture_window_mask_x) * 8); v = (v & (~(m_render_state.texture_window_mask_y * 8))) | + // ((m_render_state.texture_window_offset_y & m_render_state.texture_window_mask_y) * 8); + } else + { hw_vert.texcoord = 0; + } hw_vert.padding = 0; @@ -258,15 +266,24 @@ uniform vec2 u_transparent_alpha; in vec2 v_tex0; flat in ivec4 v_texpage; uniform sampler2D samp0; + uniform uvec4 u_texture_window; #endif out vec4 o_col0; #if TEXTURED +ivec2 ApplyTextureWindow(ivec2 coords) +{ + uint x = (uint(coords.x) & ~(u_texture_window.x * 8u)) | ((u_texture_window.z & u_texture_window.x) * 8u); + uint y = (uint(coords.y) & ~(u_texture_window.y * 8u)) | ((u_texture_window.w & u_texture_window.y) * 8u); + return ivec2(int(x), int(y)); +} + vec4 SampleFromVRAM(vec2 coord) { // from 0..1 to 0..255 ivec2 icoord = ivec2(coord * vec2(255.0)); + icoord = ApplyTextureWindow(icoord); // adjust for tightly packed palette formats ivec2 index_coord = icoord; @@ -493,7 +510,7 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices) const bool restart_line_strip = (rc_primitive == HWRenderBatch::Primitive::LineStrip); const bool needs_flush = !IsFlushed() && (m_render_state.IsTextureColorModeChanged() || m_render_state.IsTransparencyModeChanged() || - buffer_overflow || rc_changed || restart_line_strip); + m_render_state.IsTextureWindowChanged() || buffer_overflow || rc_changed || restart_line_strip); if (needs_flush) FlushRender(); @@ -544,5 +561,14 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices) m_render_state.ClearTransparencyModeChangedFlag(); } + if (m_render_state.IsTextureWindowChanged()) + { + m_batch.texture_window_values[0] = m_render_state.texture_window_mask_x; + m_batch.texture_window_values[1] = m_render_state.texture_window_mask_y; + m_batch.texture_window_values[2] = m_render_state.texture_window_offset_x; + m_batch.texture_window_values[3] = m_render_state.texture_window_offset_y; + m_render_state.ClearTextureWindowChangedFlag(); + } + LoadVertices(rc, num_vertices); } diff --git a/src/core/gpu_hw.h b/src/core/gpu_hw.h index 200c14ddd..51e279eaa 100644 --- a/src/core/gpu_hw.h +++ b/src/core/gpu_hw.h @@ -51,6 +51,7 @@ protected: u32 texture_palette_x; u32 texture_palette_y; TransparencyMode transparency_mode; + std::array texture_window_values; std::vector vertices; }; diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 57cdb4919..d63d01c84 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -358,8 +358,9 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool transparent, bool tex if (textured) { + prog.RegisterUniform("u_texture_window"); prog.RegisterUniform("samp0"); - prog.Uniform1i(2, 0); + prog.Uniform1i(3, 0); } return true; @@ -385,7 +386,11 @@ void GPU_HW_OpenGL::SetDrawState() } if (m_batch.texture_enable) + { + prog.Uniform4ui(2, m_batch.texture_window_values[0], m_batch.texture_window_values[1], + m_batch.texture_window_values[2], m_batch.texture_window_values[3]); m_vram_read_texture->Bind(); + } if (m_last_transparency_enable != m_batch.transparency_enable || (m_last_transparency_enable && m_last_transparency_mode != m_batch.transparency_mode))