mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-17 22:25:37 +00:00
GPU: Simplify batch state
This commit is contained in:
parent
d8a02d7a15
commit
1c79737021
|
@ -49,8 +49,6 @@ void GPU::SoftReset()
|
||||||
m_GPUREAD_buffer.clear();
|
m_GPUREAD_buffer.clear();
|
||||||
m_render_state = {};
|
m_render_state = {};
|
||||||
m_render_state.texture_page_changed = true;
|
m_render_state.texture_page_changed = true;
|
||||||
m_render_state.texture_color_mode_changed = true;
|
|
||||||
m_render_state.transparency_mode_changed = true;
|
|
||||||
UpdateGPUSTAT();
|
UpdateGPUSTAT();
|
||||||
UpdateCRTCConfig();
|
UpdateCRTCConfig();
|
||||||
}
|
}
|
||||||
|
@ -80,10 +78,6 @@ bool GPU::DoState(StateWrapper& sw)
|
||||||
sw.Do(&m_render_state.texpage_attribute);
|
sw.Do(&m_render_state.texpage_attribute);
|
||||||
sw.Do(&m_render_state.texlut_attribute);
|
sw.Do(&m_render_state.texlut_attribute);
|
||||||
sw.Do(&m_render_state.texture_window_value);
|
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.left);
|
||||||
sw.Do(&m_drawing_area.top);
|
sw.Do(&m_drawing_area.top);
|
||||||
|
@ -119,8 +113,6 @@ bool GPU::DoState(StateWrapper& sw)
|
||||||
if (sw.IsReading())
|
if (sw.IsReading())
|
||||||
{
|
{
|
||||||
m_render_state.texture_page_changed = true;
|
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;
|
m_render_state.texture_window_changed = true;
|
||||||
UpdateDrawingArea();
|
UpdateDrawingArea();
|
||||||
UpdateGPUSTAT();
|
UpdateGPUSTAT();
|
||||||
|
@ -709,15 +701,8 @@ void GPU::RenderState::SetFromPageAttribute(u16 value)
|
||||||
texture_page_changed |=
|
texture_page_changed |=
|
||||||
(old_page_attribute & PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK) != (value & PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK);
|
(old_page_attribute & PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK) != (value & PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK);
|
||||||
|
|
||||||
const TextureColorMode old_color_mode = texture_color_mode;
|
texture_color_mode = (static_cast<TextureMode>((value >> 7) & UINT16_C(0x03)));
|
||||||
texture_color_mode = (static_cast<TextureColorMode>((value >> 7) & UINT16_C(0x03)));
|
|
||||||
if (texture_color_mode == TextureColorMode::Reserved_Direct16Bit)
|
|
||||||
texture_color_mode = TextureColorMode::Direct16Bit;
|
|
||||||
texture_color_mode_changed |= old_color_mode != texture_color_mode;
|
|
||||||
|
|
||||||
const TransparencyMode old_transparency_mode = transparency_mode;
|
|
||||||
transparency_mode = (static_cast<TransparencyMode>((value >> 5) & UINT16_C(0x03)));
|
transparency_mode = (static_cast<TransparencyMode>((value >> 5) & UINT16_C(0x03)));
|
||||||
transparency_mode_changed = old_transparency_mode != transparency_mode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU::RenderState::SetFromPaletteAttribute(u16 value)
|
void GPU::RenderState::SetFromPaletteAttribute(u16 value)
|
||||||
|
|
|
@ -138,20 +138,33 @@ protected:
|
||||||
R16x16 = 3
|
R16x16 = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class TextureColorMode : u8
|
enum class TextureMode : u8
|
||||||
{
|
{
|
||||||
Palette4Bit = 0,
|
Palette4Bit = 0,
|
||||||
Palette8Bit = 1,
|
Palette8Bit = 1,
|
||||||
Direct16Bit = 2,
|
Direct16Bit = 2,
|
||||||
Reserved_Direct16Bit = 3
|
Reserved_Direct16Bit = 3,
|
||||||
|
|
||||||
|
// Not register values.
|
||||||
|
RawTextureBit = 4,
|
||||||
|
RawPalette4Bit = RawTextureBit | Palette4Bit,
|
||||||
|
RawPalette8Bit = RawTextureBit | Palette8Bit,
|
||||||
|
RawDirect16Bit = RawTextureBit | Direct16Bit,
|
||||||
|
Reserved_RawDirect16Bit = RawTextureBit | Reserved_Direct16Bit,
|
||||||
|
|
||||||
|
Disabled = 8 // Not a register value
|
||||||
};
|
};
|
||||||
|
|
||||||
|
IMPLEMENT_STATIC_FRIEND_ENUM_CLASS_BITWISE_OPERATORS(TextureMode);
|
||||||
|
|
||||||
enum class TransparencyMode : u8
|
enum class TransparencyMode : u8
|
||||||
{
|
{
|
||||||
HalfBackgroundPlusHalfForeground = 0,
|
HalfBackgroundPlusHalfForeground = 0,
|
||||||
BackgroundPlusForeground = 1,
|
BackgroundPlusForeground = 1,
|
||||||
BackgroundMinusForeground = 2,
|
BackgroundMinusForeground = 2,
|
||||||
BackgroundPlusQuarterForeground = 3
|
BackgroundPlusQuarterForeground = 3,
|
||||||
|
|
||||||
|
Disabled = 4 // Not a register value
|
||||||
};
|
};
|
||||||
|
|
||||||
union RenderCommand
|
union RenderCommand
|
||||||
|
@ -159,7 +172,7 @@ protected:
|
||||||
u32 bits;
|
u32 bits;
|
||||||
|
|
||||||
BitField<u32, u32, 0, 24> color_for_first_vertex;
|
BitField<u32, u32, 0, 24> color_for_first_vertex;
|
||||||
BitField<u32, bool, 24, 1> texture_blend_disable; // not valid for lines
|
BitField<u32, bool, 24, 1> raw_texture_enable; // not valid for lines
|
||||||
BitField<u32, bool, 25, 1> transparency_enable;
|
BitField<u32, bool, 25, 1> transparency_enable;
|
||||||
BitField<u32, bool, 26, 1> texture_enable;
|
BitField<u32, bool, 26, 1> texture_enable;
|
||||||
BitField<u32, DrawRectangleSize, 27, 2> rectangle_size; // only for rectangles
|
BitField<u32, DrawRectangleSize, 27, 2> rectangle_size; // only for rectangles
|
||||||
|
@ -170,7 +183,7 @@ protected:
|
||||||
|
|
||||||
// Helper functions.
|
// Helper functions.
|
||||||
bool IsTextureEnabled() const { return (primitive != Primitive::Line && texture_enable); }
|
bool IsTextureEnabled() const { return (primitive != Primitive::Line && texture_enable); }
|
||||||
bool IsTextureBlendingEnabled() const { return (IsTextureEnabled() && !texture_blend_disable); }
|
bool IsTextureBlendingEnabled() const { return (IsTextureEnabled() && !raw_texture_enable); }
|
||||||
bool IsTransparencyEnabled() const { return transparency_enable; }
|
bool IsTransparencyEnabled() const { return transparency_enable; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -269,7 +282,7 @@ protected:
|
||||||
BitField<u32, u8, 0, 4> texture_page_x_base;
|
BitField<u32, u8, 0, 4> texture_page_x_base;
|
||||||
BitField<u32, u8, 4, 1> texture_page_y_base;
|
BitField<u32, u8, 4, 1> texture_page_y_base;
|
||||||
BitField<u32, TransparencyMode, 5, 2> semi_transparency_mode;
|
BitField<u32, TransparencyMode, 5, 2> semi_transparency_mode;
|
||||||
BitField<u32, TextureColorMode, 7, 2> texture_color_mode;
|
BitField<u32, TextureMode, 7, 2> texture_color_mode;
|
||||||
BitField<u32, bool, 9, 1> dither_enable;
|
BitField<u32, bool, 9, 1> dither_enable;
|
||||||
BitField<u32, bool, 10, 1> draw_to_display_area;
|
BitField<u32, bool, 10, 1> draw_to_display_area;
|
||||||
BitField<u32, bool, 11, 1> draw_set_mask_bit;
|
BitField<u32, bool, 11, 1> draw_set_mask_bit;
|
||||||
|
@ -305,7 +318,7 @@ protected:
|
||||||
u32 texture_page_y;
|
u32 texture_page_y;
|
||||||
u32 texture_palette_x;
|
u32 texture_palette_x;
|
||||||
u32 texture_palette_y;
|
u32 texture_palette_y;
|
||||||
TextureColorMode texture_color_mode;
|
TextureMode texture_color_mode;
|
||||||
TransparencyMode transparency_mode;
|
TransparencyMode transparency_mode;
|
||||||
u8 texture_window_mask_x; // in 8 pixel steps
|
u8 texture_window_mask_x; // in 8 pixel steps
|
||||||
u8 texture_window_mask_y; // in 8 pixel steps
|
u8 texture_window_mask_y; // in 8 pixel steps
|
||||||
|
@ -320,21 +333,11 @@ protected:
|
||||||
u32 texture_window_value;
|
u32 texture_window_value;
|
||||||
|
|
||||||
bool texture_page_changed = false;
|
bool texture_page_changed = false;
|
||||||
bool texture_color_mode_changed = false;
|
|
||||||
bool transparency_mode_changed = false;
|
|
||||||
bool texture_window_changed = false;
|
bool texture_window_changed = false;
|
||||||
|
|
||||||
bool IsChanged() const { return texture_page_changed || texture_color_mode_changed || transparency_mode_changed; }
|
|
||||||
|
|
||||||
bool IsTexturePageChanged() const { return texture_page_changed; }
|
bool IsTexturePageChanged() const { return texture_page_changed; }
|
||||||
void ClearTexturePageChangedFlag() { texture_page_changed = false; }
|
void ClearTexturePageChangedFlag() { texture_page_changed = false; }
|
||||||
|
|
||||||
bool IsTextureColorModeChanged() const { return texture_color_mode_changed; }
|
|
||||||
void ClearTextureColorModeChangedFlag() { texture_color_mode_changed = false; }
|
|
||||||
|
|
||||||
bool IsTransparencyModeChanged() const { return transparency_mode_changed; }
|
|
||||||
void ClearTransparencyModeChangedFlag() { transparency_mode_changed = false; }
|
|
||||||
|
|
||||||
bool IsTextureWindowChanged() const { return texture_window_changed; }
|
bool IsTextureWindowChanged() const { return texture_window_changed; }
|
||||||
void ClearTextureWindowChangedFlag() { texture_window_changed = false; }
|
void ClearTextureWindowChangedFlag() { texture_window_changed = false; }
|
||||||
|
|
||||||
|
|
|
@ -241,21 +241,23 @@ void main()
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GPU_HW::GenerateFragmentShader(TransparencyRenderMode transparency, bool textured,
|
std::string GPU_HW::GenerateFragmentShader(HWBatchRenderMode transparency, TextureMode texture_mode)
|
||||||
TextureColorMode texture_color_mode, bool blending)
|
|
||||||
{
|
{
|
||||||
|
const TextureMode actual_texture_mode = texture_mode & ~TextureMode::RawTextureBit;
|
||||||
|
const bool raw_texture = (texture_mode & TextureMode::RawTextureBit) == TextureMode::RawTextureBit;
|
||||||
|
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
GenerateShaderHeader(ss);
|
GenerateShaderHeader(ss);
|
||||||
DefineMacro(ss, "TRANSPARENT", transparency != TransparencyRenderMode::Off);
|
DefineMacro(ss, "TRANSPARENCY", transparency != HWBatchRenderMode::TransparencyDisabled);
|
||||||
DefineMacro(ss, "TRANSPARENT_ONLY_OPAQUE", transparency == TransparencyRenderMode::OnlyOpaque);
|
DefineMacro(ss, "TRANSPARENCY_ONLY_OPAQUE", transparency == HWBatchRenderMode::OnlyOpaque);
|
||||||
DefineMacro(ss, "TRANSPARENT_ONLY_TRANSPARENT", transparency == TransparencyRenderMode::OnlyTransparent);
|
DefineMacro(ss, "TRANSPARENCY_ONLY_TRANSPARENCY", transparency == HWBatchRenderMode::OnlyTransparent);
|
||||||
DefineMacro(ss, "TEXTURED", textured);
|
DefineMacro(ss, "TEXTURED", actual_texture_mode != TextureMode::Disabled);
|
||||||
DefineMacro(ss, "PALETTE",
|
DefineMacro(ss, "PALETTE",
|
||||||
textured && (texture_color_mode == GPU::TextureColorMode::Palette4Bit ||
|
actual_texture_mode == GPU::TextureMode::Palette4Bit ||
|
||||||
texture_color_mode == GPU::TextureColorMode::Palette8Bit));
|
actual_texture_mode == GPU::TextureMode::Palette8Bit);
|
||||||
DefineMacro(ss, "PALETTE_4_BIT", textured && texture_color_mode == GPU::TextureColorMode::Palette4Bit);
|
DefineMacro(ss, "PALETTE_4_BIT", actual_texture_mode == GPU::TextureMode::Palette4Bit);
|
||||||
DefineMacro(ss, "PALETTE_8_BIT", textured && texture_color_mode == GPU::TextureColorMode::Palette8Bit);
|
DefineMacro(ss, "PALETTE_8_BIT", actual_texture_mode == GPU::TextureMode::Palette8Bit);
|
||||||
DefineMacro(ss, "BLENDING", blending);
|
DefineMacro(ss, "RAW_TEXTURE", raw_texture);
|
||||||
|
|
||||||
ss << R"(
|
ss << R"(
|
||||||
in vec3 v_col0;
|
in vec3 v_col0;
|
||||||
|
@ -334,24 +336,24 @@ void main()
|
||||||
discard;
|
discard;
|
||||||
|
|
||||||
vec3 color;
|
vec3 color;
|
||||||
#if BLENDING
|
#if RAW_TEXTURE
|
||||||
color = vec3((ivec3(v_col0 * 255.0) * ivec3(texcol.rgb * 255.0)) >> 7) / 255.0;
|
|
||||||
#else
|
|
||||||
color = texcol.rgb;
|
color = texcol.rgb;
|
||||||
|
#else
|
||||||
|
color = vec3((ivec3(v_col0 * 255.0) * ivec3(texcol.rgb * 255.0)) >> 7) / 255.0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TRANSPARENT
|
#if TRANSPARENCY
|
||||||
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
|
// Apply semitransparency. If not a semitransparent texel, destination alpha is ignored.
|
||||||
if (texcol.a != 0)
|
if (texcol.a != 0)
|
||||||
{
|
{
|
||||||
#if TRANSPARENT_ONLY_OPAQUE
|
#if TRANSPARENCY_ONLY_OPAQUE
|
||||||
discard;
|
discard;
|
||||||
#endif
|
#endif
|
||||||
o_col0 = vec4(color * u_transparent_alpha.x, u_transparent_alpha.y);
|
o_col0 = vec4(color * u_transparent_alpha.x, u_transparent_alpha.y);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if TRANSPARENT_ONLY_TRANSPARENT
|
#if TRANSPARENCY_ONLY_TRANSPARENCY
|
||||||
discard;
|
discard;
|
||||||
#endif
|
#endif
|
||||||
o_col0 = vec4(color, 0.0);
|
o_col0 = vec4(color, 0.0);
|
||||||
|
@ -361,7 +363,7 @@ void main()
|
||||||
o_col0 = vec4(color, texcol.a);
|
o_col0 = vec4(color, texcol.a);
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
#if TRANSPARENT
|
#if TRANSPARENCY
|
||||||
o_col0 = vec4(v_col0 * u_transparent_alpha.x, u_transparent_alpha.y);
|
o_col0 = vec4(v_col0 * u_transparent_alpha.x, u_transparent_alpha.y);
|
||||||
#else
|
#else
|
||||||
// Mask bit is cleared for untextured polygons.
|
// Mask bit is cleared for untextured polygons.
|
||||||
|
@ -491,20 +493,21 @@ void main()
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
GPU_HW::HWRenderBatch::Primitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc)
|
GPU_HW::HWPrimitive GPU_HW::GetPrimitiveForCommand(RenderCommand rc)
|
||||||
{
|
{
|
||||||
if (rc.primitive == Primitive::Line)
|
if (rc.primitive == Primitive::Line)
|
||||||
return rc.polyline ? HWRenderBatch::Primitive::LineStrip : HWRenderBatch::Primitive::Lines;
|
return rc.polyline ? HWPrimitive::LineStrip : HWPrimitive::Lines;
|
||||||
else if ((rc.primitive == Primitive::Polygon && rc.quad_polygon) || rc.primitive == Primitive::Rectangle)
|
else if ((rc.primitive == Primitive::Polygon && rc.quad_polygon) || rc.primitive == Primitive::Rectangle)
|
||||||
return HWRenderBatch::Primitive::TriangleStrip;
|
return HWPrimitive::TriangleStrip;
|
||||||
else
|
else
|
||||||
return HWRenderBatch::Primitive::Triangles;
|
return HWPrimitive::Triangles;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW::InvalidateVRAMReadCache() {}
|
void GPU_HW::InvalidateVRAMReadCache() {}
|
||||||
|
|
||||||
void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32* command_ptr)
|
void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32* command_ptr)
|
||||||
{
|
{
|
||||||
|
TextureMode texture_mode;
|
||||||
if (rc.texture_enable)
|
if (rc.texture_enable)
|
||||||
{
|
{
|
||||||
// extract texture lut/page
|
// extract texture lut/page
|
||||||
|
@ -529,39 +532,37 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
texture_mode = m_render_state.texture_color_mode;
|
||||||
|
if (rc.raw_texture_enable)
|
||||||
|
texture_mode |= TextureMode::RawTextureBit;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_render_state.SetFromPageAttribute(Truncate16(m_GPUSTAT.bits));
|
m_render_state.SetFromPageAttribute(Truncate16(m_GPUSTAT.bits));
|
||||||
|
texture_mode = TextureMode::Disabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
// has any state changed which requires a new batch?
|
// has any state changed which requires a new batch?
|
||||||
const bool rc_transparency_enable = rc.IsTransparencyEnabled();
|
const TransparencyMode transparency_mode =
|
||||||
const bool rc_texture_enable = rc.IsTextureEnabled();
|
rc.transparency_enable ? m_render_state.transparency_mode : TransparencyMode::Disabled;
|
||||||
const bool rc_texture_blend_enable = rc.IsTextureBlendingEnabled();
|
const HWPrimitive rc_primitive = GetPrimitiveForCommand(rc);
|
||||||
const HWRenderBatch::Primitive rc_primitive = GetPrimitiveForCommand(rc);
|
if (!IsFlushed())
|
||||||
const u32 max_added_vertices = num_vertices + 2;
|
{
|
||||||
const bool buffer_overflow = (m_batch.vertices.size() + max_added_vertices) >= MAX_BATCH_VERTEX_COUNT;
|
const u32 max_added_vertices = num_vertices + 2;
|
||||||
const bool rc_changed =
|
const bool buffer_overflow = (m_batch.vertices.size() + max_added_vertices) >= MAX_BATCH_VERTEX_COUNT;
|
||||||
m_batch.render_command_bits != rc.bits &&
|
if (buffer_overflow || rc_primitive == HWPrimitive::LineStrip || m_batch.texture_mode != texture_mode ||
|
||||||
(m_batch.transparency_enable != rc_transparency_enable || m_batch.texture_enable != rc_texture_enable ||
|
m_batch.transparency_mode != transparency_mode || m_batch.primitive != rc_primitive ||
|
||||||
m_batch.texture_blending_enable != rc_texture_blend_enable || m_batch.primitive != rc_primitive);
|
m_render_state.IsTexturePageChanged() || m_render_state.IsTextureWindowChanged())
|
||||||
const bool restart_line_strip = (rc_primitive == HWRenderBatch::Primitive::LineStrip);
|
{
|
||||||
const bool needs_flush =
|
FlushRender();
|
||||||
!IsFlushed() && (m_render_state.IsTextureColorModeChanged() || m_render_state.IsTransparencyModeChanged() ||
|
}
|
||||||
m_render_state.IsTextureWindowChanged() || buffer_overflow || rc_changed || restart_line_strip);
|
}
|
||||||
if (needs_flush)
|
|
||||||
FlushRender();
|
|
||||||
|
|
||||||
// update state
|
// update state
|
||||||
if (rc_changed)
|
m_batch.primitive = rc_primitive;
|
||||||
{
|
m_batch.texture_mode = texture_mode;
|
||||||
m_batch.render_command_bits = rc.bits;
|
m_batch.transparency_mode = transparency_mode;
|
||||||
m_batch.primitive = rc_primitive;
|
|
||||||
m_batch.transparency_enable = rc_transparency_enable;
|
|
||||||
m_batch.texture_enable = rc_texture_enable;
|
|
||||||
m_batch.texture_blending_enable = rc_texture_blend_enable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_render_state.IsTexturePageChanged())
|
if (m_render_state.IsTexturePageChanged())
|
||||||
{
|
{
|
||||||
|
@ -588,18 +589,6 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices, const u32
|
||||||
m_render_state.ClearTexturePageChangedFlag();
|
m_render_state.ClearTexturePageChangedFlag();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_render_state.IsTextureColorModeChanged())
|
|
||||||
{
|
|
||||||
m_batch.texture_color_mode = m_render_state.texture_color_mode;
|
|
||||||
m_render_state.ClearTextureColorModeChangedFlag();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_render_state.IsTransparencyModeChanged())
|
|
||||||
{
|
|
||||||
m_batch.transparency_mode = m_render_state.transparency_mode;
|
|
||||||
m_render_state.ClearTransparencyModeChangedFlag();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_render_state.IsTextureWindowChanged())
|
if (m_render_state.IsTextureWindowChanged())
|
||||||
{
|
{
|
||||||
m_batch.texture_window_values[0] = m_render_state.texture_window_mask_x;
|
m_batch.texture_window_values[0] = m_render_state.texture_window_mask_x;
|
||||||
|
|
|
@ -14,6 +14,22 @@ public:
|
||||||
virtual void Reset() override;
|
virtual void Reset() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
enum class HWPrimitive : u8
|
||||||
|
{
|
||||||
|
Lines = 0,
|
||||||
|
LineStrip = 1,
|
||||||
|
Triangles = 2,
|
||||||
|
TriangleStrip = 3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class HWBatchRenderMode : u8
|
||||||
|
{
|
||||||
|
TransparencyDisabled,
|
||||||
|
TransparentAndOpaque,
|
||||||
|
OnlyOpaque,
|
||||||
|
OnlyTransparent
|
||||||
|
};
|
||||||
|
|
||||||
struct HWVertex
|
struct HWVertex
|
||||||
{
|
{
|
||||||
s32 x;
|
s32 x;
|
||||||
|
@ -28,20 +44,8 @@ protected:
|
||||||
|
|
||||||
struct HWRenderBatch
|
struct HWRenderBatch
|
||||||
{
|
{
|
||||||
enum class Primitive : u8
|
HWPrimitive primitive;
|
||||||
{
|
TextureMode texture_mode;
|
||||||
Lines = 0,
|
|
||||||
LineStrip = 1,
|
|
||||||
Triangles = 2,
|
|
||||||
TriangleStrip = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
u32 render_command_bits;
|
|
||||||
Primitive primitive;
|
|
||||||
bool transparency_enable;
|
|
||||||
bool texture_enable;
|
|
||||||
bool texture_blending_enable;
|
|
||||||
TextureColorMode texture_color_mode;
|
|
||||||
u32 texture_page_x;
|
u32 texture_page_x;
|
||||||
u32 texture_page_y;
|
u32 texture_page_y;
|
||||||
u32 texture_palette_x;
|
u32 texture_palette_x;
|
||||||
|
@ -50,14 +54,21 @@ protected:
|
||||||
std::array<u8, 4> texture_window_values;
|
std::array<u8, 4> texture_window_values;
|
||||||
|
|
||||||
std::vector<HWVertex> vertices;
|
std::vector<HWVertex> vertices;
|
||||||
};
|
|
||||||
|
|
||||||
enum class TransparencyRenderMode
|
// We need two-pass rendering when using BG-FG blending and texturing, as the transparency can be enabled
|
||||||
{
|
// on a per-pixel basis, and the opaque pixels shouldn't be blended at all.
|
||||||
Off,
|
bool NeedsTwoPassRendering() const
|
||||||
TransparentAndOpaque,
|
{
|
||||||
OnlyOpaque,
|
return transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground &&
|
||||||
OnlyTransparent
|
texture_mode != TextureMode::Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the render mode for this batch.
|
||||||
|
HWBatchRenderMode GetRenderMode() const
|
||||||
|
{
|
||||||
|
return transparency_mode == TransparencyMode::Disabled ? HWBatchRenderMode::TransparencyDisabled :
|
||||||
|
HWBatchRenderMode::TransparentAndOpaque;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr u32 VERTEX_BUFFER_SIZE = 1 * 1024 * 1024;
|
static constexpr u32 VERTEX_BUFFER_SIZE = 1 * 1024 * 1024;
|
||||||
|
@ -89,8 +100,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GenerateVertexShader(bool textured);
|
std::string GenerateVertexShader(bool textured);
|
||||||
std::string GenerateFragmentShader(TransparencyRenderMode transparency, bool textured,
|
std::string GenerateFragmentShader(HWBatchRenderMode transparency, TextureMode texture_mode);
|
||||||
TextureColorMode texture_color_mode, bool blending);
|
|
||||||
std::string GenerateScreenQuadVertexShader();
|
std::string GenerateScreenQuadVertexShader();
|
||||||
std::string GenerateFillFragmentShader();
|
std::string GenerateFillFragmentShader();
|
||||||
std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced);
|
std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced);
|
||||||
|
@ -98,7 +108,7 @@ protected:
|
||||||
HWRenderBatch m_batch = {};
|
HWRenderBatch m_batch = {};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static HWRenderBatch::Primitive GetPrimitiveForCommand(RenderCommand rc);
|
static HWPrimitive GetPrimitiveForCommand(RenderCommand rc);
|
||||||
|
|
||||||
void GenerateShaderHeader(std::stringstream& ss);
|
void GenerateShaderHeader(std::stringstream& ss);
|
||||||
|
|
||||||
|
|
|
@ -230,22 +230,14 @@ void GPU_HW_OpenGL::CreateVertexBuffer()
|
||||||
|
|
||||||
bool GPU_HW_OpenGL::CompilePrograms()
|
bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
{
|
{
|
||||||
for (u32 transparent = 0; transparent < 4; transparent++)
|
for (u32 render_mode = 0; render_mode < 4; render_mode++)
|
||||||
{
|
{
|
||||||
for (u32 textured = 0; textured < 2; textured++)
|
for (u32 texture_mode = 0; texture_mode < 9; texture_mode++)
|
||||||
{
|
{
|
||||||
for (u32 format = 0; format < 3; format++)
|
if (!CompileProgram(m_render_programs[render_mode][texture_mode], static_cast<HWBatchRenderMode>(render_mode),
|
||||||
|
static_cast<TextureMode>(texture_mode)))
|
||||||
{
|
{
|
||||||
for (u32 blending = 0; blending < 2; blending++)
|
return false;
|
||||||
{
|
|
||||||
// TODO: eliminate duplicate shaders here
|
|
||||||
if (!CompileProgram(m_render_programs[transparent][textured][format][blending],
|
|
||||||
static_cast<TransparencyRenderMode>(transparent), ConvertToBoolUnchecked(textured),
|
|
||||||
static_cast<TextureColorMode>(format), ConvertToBoolUnchecked(blending)))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -276,11 +268,11 @@ bool GPU_HW_OpenGL::CompilePrograms()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, TransparencyRenderMode transparent, bool textured,
|
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, HWBatchRenderMode render_mode, TextureMode texture_mode)
|
||||||
TextureColorMode texture_color_mode, bool blending)
|
|
||||||
{
|
{
|
||||||
|
const bool textured = texture_mode != TextureMode::Disabled;
|
||||||
const std::string vs = GenerateVertexShader(textured);
|
const std::string vs = GenerateVertexShader(textured);
|
||||||
const std::string fs = GenerateFragmentShader(transparent, textured, texture_color_mode, blending);
|
const std::string fs = GenerateFragmentShader(render_mode, texture_mode);
|
||||||
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -313,15 +305,13 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, TransparencyRenderMode tra
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPU_HW_OpenGL::SetDrawState(TransparencyRenderMode render_mode)
|
void GPU_HW_OpenGL::SetDrawState(HWBatchRenderMode render_mode)
|
||||||
{
|
{
|
||||||
const GL::Program& prog =
|
const GL::Program& prog = m_render_programs[static_cast<u32>(render_mode)][static_cast<u32>(m_batch.texture_mode)];
|
||||||
m_render_programs[static_cast<u32>(render_mode)][BoolToUInt32(m_batch.texture_enable)]
|
|
||||||
[static_cast<u32>(m_batch.texture_color_mode)][BoolToUInt32(m_batch.texture_blending_enable)];
|
|
||||||
prog.Bind();
|
prog.Bind();
|
||||||
|
|
||||||
prog.Uniform2i(0, m_drawing_offset.x, m_drawing_offset.y);
|
prog.Uniform2i(0, m_drawing_offset.x, m_drawing_offset.y);
|
||||||
if (m_batch.transparency_enable)
|
if (m_batch.transparency_mode != TransparencyMode::Disabled)
|
||||||
{
|
{
|
||||||
static constexpr float transparent_alpha[4][2] = {{0.5f, 0.5f}, {1.0f, 1.0f}, {1.0f, 1.0f}, {0.25f, 1.0f}};
|
static constexpr float transparent_alpha[4][2] = {{0.5f, 0.5f}, {1.0f, 1.0f}, {1.0f, 1.0f}, {0.25f, 1.0f}};
|
||||||
prog.Uniform2fv(1, transparent_alpha[static_cast<u32>(m_batch.transparency_mode)]);
|
prog.Uniform2fv(1, transparent_alpha[static_cast<u32>(m_batch.transparency_mode)]);
|
||||||
|
@ -332,14 +322,14 @@ void GPU_HW_OpenGL::SetDrawState(TransparencyRenderMode render_mode)
|
||||||
prog.Uniform2fv(1, disabled_alpha);
|
prog.Uniform2fv(1, disabled_alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_batch.texture_enable)
|
if (m_batch.texture_mode != TextureMode::Disabled)
|
||||||
{
|
{
|
||||||
prog.Uniform4ui(2, m_batch.texture_window_values[0], m_batch.texture_window_values[1],
|
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_batch.texture_window_values[2], m_batch.texture_window_values[3]);
|
||||||
m_vram_read_texture->Bind();
|
m_vram_read_texture->Bind();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (render_mode == TransparencyRenderMode::Off || render_mode == TransparencyRenderMode::OnlyOpaque)
|
if (m_batch.transparency_mode == TransparencyMode::Disabled || render_mode == HWBatchRenderMode::OnlyOpaque)
|
||||||
{
|
{
|
||||||
glDisable(GL_BLEND);
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
@ -644,18 +634,16 @@ void GPU_HW_OpenGL::FlushRender()
|
||||||
|
|
||||||
static constexpr std::array<GLenum, 4> gl_primitives = {{GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP}};
|
static constexpr std::array<GLenum, 4> gl_primitives = {{GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP}};
|
||||||
|
|
||||||
if (m_batch.transparency_enable && m_batch.texture_enable &&
|
if (m_batch.NeedsTwoPassRendering())
|
||||||
m_batch.transparency_mode == GPU::TransparencyMode::BackgroundMinusForeground)
|
|
||||||
{
|
{
|
||||||
SetDrawState(TransparencyRenderMode::OnlyTransparent);
|
SetDrawState(HWBatchRenderMode::OnlyTransparent);
|
||||||
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
||||||
SetDrawState(TransparencyRenderMode::OnlyOpaque);
|
SetDrawState(HWBatchRenderMode::OnlyOpaque);
|
||||||
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SetDrawState(m_batch.transparency_enable ? TransparencyRenderMode::TransparentAndOpaque :
|
SetDrawState(m_batch.GetRenderMode());
|
||||||
TransparencyRenderMode::Off);
|
|
||||||
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
glDrawArrays(gl_primitives[static_cast<u8>(m_batch.primitive)], 0, static_cast<GLsizei>(m_batch.vertices.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,8 @@ private:
|
||||||
void CreateVertexBuffer();
|
void CreateVertexBuffer();
|
||||||
|
|
||||||
bool CompilePrograms();
|
bool CompilePrograms();
|
||||||
bool CompileProgram(GL::Program& prog, TransparencyRenderMode transparent, bool textured,
|
bool CompileProgram(GL::Program& prog, HWBatchRenderMode render_mode, TextureMode texture_mode);
|
||||||
TextureColorMode texture_color_mode, bool blending);
|
void SetDrawState(HWBatchRenderMode render_mode);
|
||||||
void SetDrawState(TransparencyRenderMode render_mode);
|
|
||||||
|
|
||||||
// downsample texture - used for readbacks at >1xIR.
|
// downsample texture - used for readbacks at >1xIR.
|
||||||
std::unique_ptr<GL::Texture> m_vram_texture;
|
std::unique_ptr<GL::Texture> m_vram_texture;
|
||||||
|
@ -71,8 +70,8 @@ private:
|
||||||
bool m_drawing_area_changed = true;
|
bool m_drawing_area_changed = true;
|
||||||
bool m_show_renderer_statistics = false;
|
bool m_show_renderer_statistics = false;
|
||||||
|
|
||||||
std::array<std::array<std::array<std::array<GL::Program, 2>, 3>, 2>, 4> m_render_programs;
|
std::array<std::array<GL::Program, 9>, 4> m_render_programs; // [render_mode][texture_mode]
|
||||||
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]
|
||||||
|
|
||||||
GLStats m_stats = {};
|
GLStats m_stats = {};
|
||||||
GLStats m_last_stats = {};
|
GLStats m_last_stats = {};
|
||||||
|
|
|
@ -417,7 +417,7 @@ void GPU_SW::ShadePixel(RenderCommand rc, u32 x, u32 y, u8 color_r, u8 color_g,
|
||||||
VRAMPixel texture_color;
|
VRAMPixel texture_color;
|
||||||
switch (m_render_state.texture_color_mode)
|
switch (m_render_state.texture_color_mode)
|
||||||
{
|
{
|
||||||
case GPU::TextureColorMode::Palette4Bit:
|
case GPU::TextureMode::Palette4Bit:
|
||||||
{
|
{
|
||||||
const u16 palette_value =
|
const u16 palette_value =
|
||||||
GetPixel(std::min<u32>(m_render_state.texture_page_x + ZeroExtend32(texcoord_x / 4), VRAM_WIDTH - 1),
|
GetPixel(std::min<u32>(m_render_state.texture_page_x + ZeroExtend32(texcoord_x / 4), VRAM_WIDTH - 1),
|
||||||
|
@ -429,7 +429,7 @@ void GPU_SW::ShadePixel(RenderCommand rc, u32 x, u32 y, u8 color_r, u8 color_g,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GPU::TextureColorMode::Palette8Bit:
|
case GPU::TextureMode::Palette8Bit:
|
||||||
{
|
{
|
||||||
const u16 palette_value =
|
const u16 palette_value =
|
||||||
GetPixel(std::min<u32>(m_render_state.texture_page_x + ZeroExtend32(texcoord_x / 2), VRAM_WIDTH - 1),
|
GetPixel(std::min<u32>(m_render_state.texture_page_x + ZeroExtend32(texcoord_x / 2), VRAM_WIDTH - 1),
|
||||||
|
@ -455,7 +455,7 @@ void GPU_SW::ShadePixel(RenderCommand rc, u32 x, u32 y, u8 color_r, u8 color_g,
|
||||||
|
|
||||||
transparent = texture_color.c;
|
transparent = texture_color.c;
|
||||||
|
|
||||||
if (rc.texture_blend_disable)
|
if (rc.raw_texture_enable)
|
||||||
{
|
{
|
||||||
color.bits = texture_color.bits;
|
color.bits = texture_color.bits;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue