mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 07:35:41 +00:00
GPU: Implement interlaced VRAM fills
This commit is contained in:
parent
2aecb570c1
commit
c483a78889
|
@ -893,7 +893,7 @@ void GPU::ReadVRAM(u32 x, u32 y, u32 width, u32 height) {}
|
||||||
void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
{
|
{
|
||||||
const u16 color16 = RGBA8888ToRGBA5551(color);
|
const u16 color16 = RGBA8888ToRGBA5551(color);
|
||||||
if ((x + width) <= VRAM_WIDTH)
|
if ((x + width) <= VRAM_WIDTH && !IsInterlacedRenderingEnabled())
|
||||||
{
|
{
|
||||||
for (u32 yoffs = 0; yoffs < height; yoffs++)
|
for (u32 yoffs = 0; yoffs < height; yoffs++)
|
||||||
{
|
{
|
||||||
|
@ -901,6 +901,26 @@ void GPU::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
std::fill_n(&m_vram_ptr[row * VRAM_WIDTH + x], width, color16);
|
std::fill_n(&m_vram_ptr[row * VRAM_WIDTH + x], width, color16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (IsInterlacedRenderingEnabled())
|
||||||
|
{
|
||||||
|
// Hardware tests show that fills seem to break on the first two lines when the offset matches the displayed field.
|
||||||
|
if (IsRasterScanlinePending())
|
||||||
|
Synchronize();
|
||||||
|
const u32 active_field = GetInterlacedField();
|
||||||
|
for (u32 yoffs = 0; yoffs < height; yoffs++)
|
||||||
|
{
|
||||||
|
const u32 row = (y + yoffs) % VRAM_HEIGHT;
|
||||||
|
if ((row & u32(1)) == active_field)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
u16* row_ptr = &m_vram_ptr[row * VRAM_WIDTH];
|
||||||
|
for (u32 xoffs = 0; xoffs < width; xoffs++)
|
||||||
|
{
|
||||||
|
const u32 col = (x + xoffs) % VRAM_WIDTH;
|
||||||
|
row_ptr[col] = color16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (u32 yoffs = 0; yoffs < height; yoffs++)
|
for (u32 yoffs = 0; yoffs < height; yoffs++)
|
||||||
|
|
|
@ -330,7 +330,16 @@ protected:
|
||||||
void Execute(TickCount ticks);
|
void Execute(TickCount ticks);
|
||||||
|
|
||||||
/// Returns true if scanout should be interlaced.
|
/// Returns true if scanout should be interlaced.
|
||||||
bool IsDisplayInterlaced() const { return !m_force_progressive_scan && m_GPUSTAT.In480iMode(); }
|
ALWAYS_INLINE bool IsInterlacedDisplayEnabled() const { return (!m_force_progressive_scan) & m_GPUSTAT.In480iMode(); }
|
||||||
|
|
||||||
|
/// Returns true if interlaced rendering is enabled and force progressive scan is disabled.
|
||||||
|
ALWAYS_INLINE bool IsInterlacedRenderingEnabled() const
|
||||||
|
{
|
||||||
|
return (!m_force_progressive_scan) & m_GPUSTAT.SkipDrawingToActiveField();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns 0 if the currently-rendered field is even, otherwise 1.
|
||||||
|
ALWAYS_INLINE u32 GetInterlacedField() const { return BoolToUInt32(m_GPUSTAT.displaying_odd_line); }
|
||||||
|
|
||||||
/// Sets/decodes GP0(E1h) (set draw mode).
|
/// Sets/decodes GP0(E1h) (set draw mode).
|
||||||
void SetDrawMode(u16 bits);
|
void SetDrawMode(u16 bits);
|
||||||
|
|
|
@ -306,7 +306,7 @@ bool GPU::HandleRenderCommand(const u32*& command_ptr, u32 command_size)
|
||||||
primitive_names[static_cast<u8>(rc.primitive.GetValue())], ZeroExtend32(num_vertices),
|
primitive_names[static_cast<u8>(rc.primitive.GetValue())], ZeroExtend32(num_vertices),
|
||||||
ZeroExtend32(words_per_vertex));
|
ZeroExtend32(words_per_vertex));
|
||||||
|
|
||||||
if (m_GPUSTAT.SkipDrawingToActiveField() && IsRasterScanlinePending())
|
if (IsInterlacedRenderingEnabled() && IsRasterScanlinePending())
|
||||||
Synchronize();
|
Synchronize();
|
||||||
|
|
||||||
DispatchRenderCommand(rc, num_vertices, command_ptr);
|
DispatchRenderCommand(rc, num_vertices, command_ptr);
|
||||||
|
|
|
@ -541,10 +541,10 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32
|
||||||
m_batch_ubo_dirty = true;
|
m_batch_ubo_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_batch.interlacing = m_GPUSTAT.SkipDrawingToActiveField();
|
m_batch.interlacing = IsInterlacedRenderingEnabled();
|
||||||
if (m_batch.interlacing)
|
if (m_batch.interlacing)
|
||||||
{
|
{
|
||||||
const u32 displayed_field = BoolToUInt32(m_GPUSTAT.displaying_odd_line);
|
const u32 displayed_field = GetInterlacedField();
|
||||||
m_batch_ubo_dirty |= (m_batch_ubo_data.u_interlaced_displayed_field != displayed_field);
|
m_batch_ubo_dirty |= (m_batch_ubo_data.u_interlaced_displayed_field != displayed_field);
|
||||||
m_batch_ubo_data.u_interlaced_displayed_field = displayed_field;
|
m_batch_ubo_data.u_interlaced_displayed_field = displayed_field;
|
||||||
}
|
}
|
||||||
|
|
|
@ -377,8 +377,13 @@ bool GPU_HW_D3D11::CompileShaders()
|
||||||
if (!m_copy_pixel_shader)
|
if (!m_copy_pixel_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_fill_pixel_shader = m_shader_cache.GetPixelShader(m_device.Get(), shadergen.GenerateFillFragmentShader());
|
m_vram_fill_pixel_shader = m_shader_cache.GetPixelShader(m_device.Get(), shadergen.GenerateFillFragmentShader());
|
||||||
if (!m_fill_pixel_shader)
|
if (!m_vram_fill_pixel_shader)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_vram_interlaced_fill_pixel_shader =
|
||||||
|
m_shader_cache.GetPixelShader(m_device.Get(), shadergen.GenerateInterlacedFillFragmentShader());
|
||||||
|
if (!m_vram_interlaced_fill_pixel_shader)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
m_vram_read_pixel_shader = m_shader_cache.GetPixelShader(m_device.Get(), shadergen.GenerateVRAMReadFragmentShader());
|
m_vram_read_pixel_shader = m_shader_cache.GetPixelShader(m_device.Get(), shadergen.GenerateVRAMReadFragmentShader());
|
||||||
|
@ -542,7 +547,7 @@ void GPU_HW_D3D11::UpdateDisplay()
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * m_resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * m_resolution_scale;
|
||||||
const bool interlaced = IsDisplayInterlaced();
|
const bool interlaced = IsInterlacedDisplayEnabled();
|
||||||
|
|
||||||
if (m_GPUSTAT.display_disable)
|
if (m_GPUSTAT.display_disable)
|
||||||
{
|
{
|
||||||
|
@ -559,7 +564,7 @@ void GPU_HW_D3D11::UpdateDisplay()
|
||||||
m_context->OMSetRenderTargets(1, m_display_texture.GetD3DRTVArray(), nullptr);
|
m_context->OMSetRenderTargets(1, m_display_texture.GetD3DRTVArray(), nullptr);
|
||||||
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
|
m_context->PSSetShaderResources(0, 1, m_vram_texture.GetD3DSRVArray());
|
||||||
|
|
||||||
const u32 reinterpret_field_offset = BoolToUInt32(m_GPUSTAT.displaying_odd_line);
|
const u32 reinterpret_field_offset = GetInterlacedField();
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
||||||
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
||||||
const u32 uniforms[4] = {reinterpret_field_offset, reinterpret_start_x};
|
const u32 uniforms[4] = {reinterpret_field_offset, reinterpret_start_x};
|
||||||
|
@ -634,12 +639,21 @@ void GPU_HW_D3D11::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
if (!m_true_color)
|
if (!m_true_color)
|
||||||
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
||||||
|
|
||||||
float uniforms[4];
|
struct Uniforms
|
||||||
std::tie(uniforms[0], uniforms[1], uniforms[2], uniforms[3]) = RGBA8ToFloat(color);
|
{
|
||||||
|
float u_fill_color[4];
|
||||||
|
u32 u_interlaced_displayed_field;
|
||||||
|
};
|
||||||
|
Uniforms uniforms;
|
||||||
|
std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) =
|
||||||
|
RGBA8ToFloat(color);
|
||||||
|
uniforms.u_interlaced_displayed_field = GetInterlacedField();
|
||||||
|
|
||||||
SetViewportAndScissor(x * m_resolution_scale, y * m_resolution_scale, width * m_resolution_scale,
|
SetViewportAndScissor(x * m_resolution_scale, y * m_resolution_scale, width * m_resolution_scale,
|
||||||
height * m_resolution_scale);
|
height * m_resolution_scale);
|
||||||
DrawUtilityShader(m_fill_pixel_shader.Get(), uniforms, sizeof(uniforms));
|
DrawUtilityShader(IsInterlacedRenderingEnabled() ? m_vram_interlaced_fill_pixel_shader.Get() :
|
||||||
|
m_vram_fill_pixel_shader.Get(),
|
||||||
|
&uniforms, sizeof(uniforms));
|
||||||
|
|
||||||
RestoreGraphicsAPIState();
|
RestoreGraphicsAPIState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,8 @@ private:
|
||||||
|
|
||||||
ComPtr<ID3D11VertexShader> m_screen_quad_vertex_shader;
|
ComPtr<ID3D11VertexShader> m_screen_quad_vertex_shader;
|
||||||
ComPtr<ID3D11PixelShader> m_copy_pixel_shader;
|
ComPtr<ID3D11PixelShader> m_copy_pixel_shader;
|
||||||
ComPtr<ID3D11PixelShader> m_fill_pixel_shader;
|
ComPtr<ID3D11PixelShader> m_vram_fill_pixel_shader;
|
||||||
|
ComPtr<ID3D11PixelShader> m_vram_interlaced_fill_pixel_shader;
|
||||||
ComPtr<ID3D11PixelShader> m_vram_read_pixel_shader;
|
ComPtr<ID3D11PixelShader> m_vram_read_pixel_shader;
|
||||||
ComPtr<ID3D11PixelShader> m_vram_write_pixel_shader;
|
ComPtr<ID3D11PixelShader> m_vram_write_pixel_shader;
|
||||||
std::array<std::array<ComPtr<ID3D11PixelShader>, 2>, 2> m_display_pixel_shaders; // [depth_24][interlaced]
|
std::array<std::array<ComPtr<ID3D11PixelShader>, 2>, 2> m_display_pixel_shaders; // [depth_24][interlaced]
|
||||||
|
|
|
@ -367,13 +367,25 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
|
|
||||||
prog->Bind();
|
prog->Bind();
|
||||||
prog->Uniform1i("samp0", 0);
|
prog->Uniform1i("samp0", 0);
|
||||||
|
|
||||||
m_display_programs[depth_24bit][interlaced] = std::move(*prog);
|
m_display_programs[depth_24bit][interlaced] = std::move(*prog);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<GL::Program> prog = m_shader_cache.GetProgram(
|
std::optional<GL::Program> prog =
|
||||||
shadergen.GenerateScreenQuadVertexShader(), shadergen.GenerateVRAMReadFragmentShader(), [this](GL::Program& prog) {
|
m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(),
|
||||||
|
shadergen.GenerateInterlacedFillFragmentShader(), [this](GL::Program& prog) {
|
||||||
|
if (!m_is_gles)
|
||||||
|
prog.BindFragData(0, "o_col0");
|
||||||
|
});
|
||||||
|
if (!prog)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
prog->BindUniformBlock("UBOBlock", 1);
|
||||||
|
prog->Bind();
|
||||||
|
m_vram_interlaced_fill_program = std::move(*prog);
|
||||||
|
|
||||||
|
prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(),
|
||||||
|
shadergen.GenerateVRAMReadFragmentShader(), [this](GL::Program& prog) {
|
||||||
if (!m_is_gles)
|
if (!m_is_gles)
|
||||||
prog.BindFragData(0, "o_col0");
|
prog.BindFragData(0, "o_col0");
|
||||||
});
|
});
|
||||||
|
@ -383,7 +395,6 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
prog->BindUniformBlock("UBOBlock", 1);
|
prog->BindUniformBlock("UBOBlock", 1);
|
||||||
prog->Bind();
|
prog->Bind();
|
||||||
prog->Uniform1i("samp0", 0);
|
prog->Uniform1i("samp0", 0);
|
||||||
|
|
||||||
m_vram_read_program = std::move(*prog);
|
m_vram_read_program = std::move(*prog);
|
||||||
|
|
||||||
if (m_supports_texture_buffer)
|
if (m_supports_texture_buffer)
|
||||||
|
@ -399,7 +410,6 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
prog->BindUniformBlock("UBOBlock", 1);
|
prog->BindUniformBlock("UBOBlock", 1);
|
||||||
prog->Bind();
|
prog->Bind();
|
||||||
prog->Uniform1i("samp0", 0);
|
prog->Uniform1i("samp0", 0);
|
||||||
|
|
||||||
m_vram_write_program = std::move(*prog);
|
m_vram_write_program = std::move(*prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -490,7 +500,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * m_resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * m_resolution_scale;
|
||||||
const bool interlaced = IsDisplayInterlaced();
|
const bool interlaced = IsInterlacedDisplayEnabled();
|
||||||
|
|
||||||
if (m_GPUSTAT.display_disable)
|
if (m_GPUSTAT.display_disable)
|
||||||
{
|
{
|
||||||
|
@ -516,7 +526,7 @@ void GPU_HW_OpenGL::UpdateDisplay()
|
||||||
const u32 scaled_flipped_vram_offset_y =
|
const u32 scaled_flipped_vram_offset_y =
|
||||||
m_vram_texture.GetHeight() - scaled_vram_offset_y - scaled_display_height;
|
m_vram_texture.GetHeight() - scaled_vram_offset_y - scaled_display_height;
|
||||||
|
|
||||||
const u32 reinterpret_field_offset = BoolToUInt32(m_GPUSTAT.displaying_odd_line);
|
const u32 reinterpret_field_offset = GetInterlacedField();
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
||||||
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
||||||
const u32 uniforms[4] = {reinterpret_field_offset, reinterpret_start_x};
|
const u32 uniforms[4] = {reinterpret_field_offset, reinterpret_start_x};
|
||||||
|
@ -600,12 +610,33 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
if (!m_true_color)
|
if (!m_true_color)
|
||||||
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
||||||
|
|
||||||
|
// fast path when not using interlaced rendering
|
||||||
|
if (!IsInterlacedRenderingEnabled())
|
||||||
|
{
|
||||||
const auto [r, g, b, a] = RGBA8ToFloat(color);
|
const auto [r, g, b, a] = RGBA8ToFloat(color);
|
||||||
glClearColor(r, g, b, a);
|
glClearColor(r, g, b, a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
SetScissorFromDrawingArea();
|
SetScissorFromDrawingArea();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct Uniforms
|
||||||
|
{
|
||||||
|
float u_fill_color[4];
|
||||||
|
u32 u_interlaced_displayed_field;
|
||||||
|
};
|
||||||
|
Uniforms uniforms;
|
||||||
|
std::tie(uniforms.u_fill_color[0], uniforms.u_fill_color[1], uniforms.u_fill_color[2], uniforms.u_fill_color[3]) =
|
||||||
|
RGBA8ToFloat(color);
|
||||||
|
uniforms.u_interlaced_displayed_field = GetInterlacedField();
|
||||||
|
|
||||||
|
m_vram_interlaced_fill_program.Bind();
|
||||||
|
UploadUniformBlock(&uniforms, sizeof(uniforms));
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
|
||||||
|
RestoreGraphicsAPIState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,6 +79,7 @@ private:
|
||||||
std::array<std::array<std::array<std::array<GL::Program, 2>, 2>, 9>, 4>
|
std::array<std::array<std::array<std::array<GL::Program, 2>, 2>, 9>, 4>
|
||||||
m_render_programs; // [render_mode][texture_mode][dithering][interlacing]
|
m_render_programs; // [render_mode][texture_mode][dithering][interlacing]
|
||||||
std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced]
|
std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced]
|
||||||
|
GL::Program m_vram_interlaced_fill_program;
|
||||||
GL::Program m_vram_read_program;
|
GL::Program m_vram_read_program;
|
||||||
GL::Program m_vram_write_program;
|
GL::Program m_vram_write_program;
|
||||||
|
|
||||||
|
|
|
@ -253,7 +253,17 @@ bool GPU_HW_OpenGL_ES::CompilePrograms()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<GL::Program> prog =
|
std::optional<GL::Program> prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(),
|
||||||
|
shadergen.GenerateInterlacedFillFragmentShader());
|
||||||
|
if (!prog)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
prog->Bind();
|
||||||
|
prog->RegisterUniform("u_fill_color");
|
||||||
|
prog->RegisterUniform("u_u_interlaced_displayed_field");
|
||||||
|
m_vram_interlaced_fill_program = std::move(*prog);
|
||||||
|
|
||||||
|
prog =
|
||||||
m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), shadergen.GenerateVRAMReadFragmentShader());
|
m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), shadergen.GenerateVRAMReadFragmentShader());
|
||||||
if (!prog)
|
if (!prog)
|
||||||
return false;
|
return false;
|
||||||
|
@ -357,7 +367,7 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
|
||||||
const u32 display_height = m_crtc_state.display_vram_height;
|
const u32 display_height = m_crtc_state.display_vram_height;
|
||||||
const u32 scaled_display_width = display_width * m_resolution_scale;
|
const u32 scaled_display_width = display_width * m_resolution_scale;
|
||||||
const u32 scaled_display_height = display_height * m_resolution_scale;
|
const u32 scaled_display_height = display_height * m_resolution_scale;
|
||||||
const bool interlaced = IsDisplayInterlaced();
|
const bool interlaced = IsInterlacedDisplayEnabled();
|
||||||
|
|
||||||
if (m_GPUSTAT.display_disable)
|
if (m_GPUSTAT.display_disable)
|
||||||
{
|
{
|
||||||
|
@ -385,7 +395,7 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
|
||||||
const u32 scaled_flipped_vram_offset_y =
|
const u32 scaled_flipped_vram_offset_y =
|
||||||
m_vram_texture.GetHeight() - scaled_vram_offset_y - scaled_display_height;
|
m_vram_texture.GetHeight() - scaled_vram_offset_y - scaled_display_height;
|
||||||
|
|
||||||
const u32 reinterpret_field_offset = BoolToUInt32(m_GPUSTAT.displaying_odd_line);
|
const u32 reinterpret_field_offset = GetInterlacedField();
|
||||||
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
const u32 reinterpret_start_x = m_crtc_state.regs.X * m_resolution_scale;
|
||||||
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
const u32 reinterpret_width = scaled_display_width + (m_crtc_state.display_vram_left - m_crtc_state.regs.X);
|
||||||
|
|
||||||
|
@ -469,11 +479,22 @@ void GPU_HW_OpenGL_ES::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
|
||||||
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
color = RGBA5551ToRGBA8888(RGBA8888ToRGBA5551(color));
|
||||||
|
|
||||||
const auto [r, g, b, a] = RGBA8ToFloat(color);
|
const auto [r, g, b, a] = RGBA8ToFloat(color);
|
||||||
|
|
||||||
|
if (!IsInterlacedRenderingEnabled())
|
||||||
|
{
|
||||||
glClearColor(r, g, b, a);
|
glClearColor(r, g, b, a);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
SetScissorFromDrawingArea();
|
SetScissorFromDrawingArea();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_vram_interlaced_fill_program.Bind();
|
||||||
|
m_vram_interlaced_fill_program.Uniform4f(0, r, g, b, a);
|
||||||
|
m_vram_interlaced_fill_program.Uniform1i(1, GetInterlacedField());
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||||
|
RestoreGraphicsAPIState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL_ES::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
void GPU_HW_OpenGL_ES::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,5 +67,6 @@ private:
|
||||||
std::array<std::array<std::array<std::array<GL::Program, 2>, 2>, 9>, 4>
|
std::array<std::array<std::array<std::array<GL::Program, 2>, 2>, 9>, 4>
|
||||||
m_render_programs; // [render_mode][texture_mode][dithering][interlacing]
|
m_render_programs; // [render_mode][texture_mode][dithering][interlacing]
|
||||||
std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced]
|
std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced]
|
||||||
|
GL::Program m_vram_interlaced_fill_program;
|
||||||
GL::Program m_vram_read_program;
|
GL::Program m_vram_read_program;
|
||||||
};
|
};
|
||||||
|
|
|
@ -523,7 +523,7 @@ float4 SampleFromVRAM(int4 texpage, int2 icoord)
|
||||||
float oalpha;
|
float oalpha;
|
||||||
|
|
||||||
#if INTERLACING
|
#if INTERLACING
|
||||||
if (((int(v_pos.y) / RESOLUTION_SCALE) & 1) == u_interlaced_displayed_field)
|
if (((fixYCoord(int(v_pos.y)) / RESOLUTION_SCALE) & 1) == u_interlaced_displayed_field)
|
||||||
discard;
|
discard;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -732,6 +732,26 @@ std::string GPU_HW_ShaderGen::GenerateFillFragmentShader()
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GPU_HW_ShaderGen::GenerateInterlacedFillFragmentShader()
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
WriteHeader(ss);
|
||||||
|
WriteCommonFunctions(ss);
|
||||||
|
DeclareUniformBuffer(ss, {"float4 u_fill_color", "int u_interlaced_displayed_field"});
|
||||||
|
DeclareFragmentEntryPoint(ss, 0, 1, {}, true, false);
|
||||||
|
|
||||||
|
ss << R"(
|
||||||
|
{
|
||||||
|
if (((fixYCoord(int(v_pos.y)) / RESOLUTION_SCALE) & 1) == u_interlaced_displayed_field)
|
||||||
|
discard;
|
||||||
|
|
||||||
|
o_col0 = u_fill_color;
|
||||||
|
}
|
||||||
|
)";
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string GPU_HW_ShaderGen::GenerateCopyFragmentShader()
|
std::string GPU_HW_ShaderGen::GenerateCopyFragmentShader()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -767,7 +787,7 @@ std::string GPU_HW_ShaderGen::GenerateDisplayFragmentShader(bool depth_24bit, bo
|
||||||
int2 icoords = int2(v_pos.xy);
|
int2 icoords = int2(v_pos.xy);
|
||||||
|
|
||||||
#if INTERLACED
|
#if INTERLACED
|
||||||
if (((icoords.y / RESOLUTION_SCALE) & 1) != u_field_offset)
|
if (((fixYCoord(icoords.y) / RESOLUTION_SCALE) & 1) != u_field_offset)
|
||||||
discard;
|
discard;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ public:
|
||||||
std::string GenerateBatchLineExpandGeometryShader();
|
std::string GenerateBatchLineExpandGeometryShader();
|
||||||
std::string GenerateScreenQuadVertexShader();
|
std::string GenerateScreenQuadVertexShader();
|
||||||
std::string GenerateFillFragmentShader();
|
std::string GenerateFillFragmentShader();
|
||||||
|
std::string GenerateInterlacedFillFragmentShader();
|
||||||
std::string GenerateCopyFragmentShader();
|
std::string GenerateCopyFragmentShader();
|
||||||
std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced);
|
std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced);
|
||||||
std::string GenerateVRAMReadFragmentShader();
|
std::string GenerateVRAMReadFragmentShader();
|
||||||
|
|
|
@ -574,11 +574,8 @@ void GPU_SW::ShadePixel(u32 x, u32 y, u8 color_r, u8 color_g, u8 color_b, u8 tex
|
||||||
if ((bg_color.bits & mask_and) != 0)
|
if ((bg_color.bits & mask_and) != 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_GPUSTAT.SkipDrawingToActiveField() &&
|
if (IsInterlacedRenderingEnabled() && GetInterlacedField() == (static_cast<u32>(y) & 1u))
|
||||||
BoolToUInt32(m_GPUSTAT.displaying_odd_line) == (static_cast<u32>(y) & 1u))
|
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
SetPixel(static_cast<u32>(x), static_cast<u32>(y), color.bits | m_GPUSTAT.GetMaskOR());
|
SetPixel(static_cast<u32>(x), static_cast<u32>(y), color.bits | m_GPUSTAT.GetMaskOR());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue