GPU: Enable batching of polygons with the different texture pages

This commit is contained in:
Connor McLaughlin 2019-09-27 21:20:35 +10:00
parent 69f6788f9f
commit c0a3a4176d
5 changed files with 63 additions and 38 deletions

View File

@ -39,7 +39,8 @@ void GPU::SoftReset()
m_crtc_state.regs.horizontal_display_range = 0xC60260; m_crtc_state.regs.horizontal_display_range = 0xC60260;
m_crtc_state.regs.vertical_display_range = 0x3FC10; m_crtc_state.regs.vertical_display_range = 0x3FC10;
m_render_state = {}; m_render_state = {};
m_render_state.texture_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.transparency_mode_changed = true;
UpdateGPUSTAT(); UpdateGPUSTAT();
UpdateCRTCConfig(); UpdateCRTCConfig();
@ -66,7 +67,8 @@ bool GPU::DoState(StateWrapper& sw)
sw.Do(&m_render_state.texture_y_flip); sw.Do(&m_render_state.texture_y_flip);
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_changed); 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.transparency_mode_changed);
sw.Do(&m_drawing_area.left); sw.Do(&m_drawing_area.left);
@ -102,7 +104,8 @@ bool GPU::DoState(StateWrapper& sw)
if (sw.IsReading()) if (sw.IsReading())
{ {
m_render_state.texture_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.transparency_mode_changed = true;
UpdateGPUSTAT(); UpdateGPUSTAT();
} }
@ -326,8 +329,6 @@ void GPU::Execute(TickCount ticks)
m_timers->SetGate(HBLANK_TIMER_INDEX, new_vblank); m_timers->SetGate(HBLANK_TIMER_INDEX, new_vblank);
} }
// alternating even line bit in 240-line mode // alternating even line bit in 240-line mode
if (!m_crtc_state.vertical_resolution) if (!m_crtc_state.vertical_resolution)
m_GPUSTAT.drawing_even_line = ConvertToBoolUnchecked(m_crtc_state.current_scanline & u32(1)); m_GPUSTAT.drawing_even_line = ConvertToBoolUnchecked(m_crtc_state.current_scanline & u32(1));
@ -439,8 +440,7 @@ void GPU::WriteGP0(u32 value)
{ {
m_drawing_area.right = param & UINT32_C(0x3FF); m_drawing_area.right = param & UINT32_C(0x3FF);
m_drawing_area.bottom = (param >> 10) & UINT32_C(0x1FF); m_drawing_area.bottom = (param >> 10) & UINT32_C(0x1FF);
Log_DebugPrintf("Set drawing area bottom-right: (%u, %u)", m_drawing_area.right, Log_DebugPrintf("Set drawing area bottom-right: (%u, %u)", m_drawing_area.right, m_drawing_area.bottom);
m_drawing_area.bottom);
} }
break; break;
@ -785,14 +785,17 @@ void GPU::RenderState::SetFromPageAttribute(u16 value)
if (texpage_attribute == value) if (texpage_attribute == value)
return; return;
texpage_attribute = value;
texture_page_x = static_cast<s32>(ZeroExtend32(value & UINT16_C(0x0F)) * UINT32_C(64)); texture_page_x = static_cast<s32>(ZeroExtend32(value & UINT16_C(0x0F)) * UINT32_C(64));
texture_page_y = static_cast<s32>(ZeroExtend32((value >> 4) & UINT16_C(1)) * UINT32_C(256)); texture_page_y = static_cast<s32>(ZeroExtend32((value >> 4) & UINT16_C(1)) * UINT32_C(256));
texture_page_changed |=
(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<TextureColorMode>((value >> 7) & UINT16_C(0x03))); texture_color_mode = (static_cast<TextureColorMode>((value >> 7) & UINT16_C(0x03)));
if (texture_color_mode == TextureColorMode::Reserved_Direct16Bit) if (texture_color_mode == TextureColorMode::Reserved_Direct16Bit)
texture_color_mode = TextureColorMode::Direct16Bit; texture_color_mode = TextureColorMode::Direct16Bit;
texture_color_mode_changed |= old_color_mode != texture_color_mode;
texpage_attribute = value;
texture_changed |= (old_page_attribute & PAGE_ATTRIBUTE_TEXTURE_MASK) != (value & PAGE_ATTRIBUTE_TEXTURE_MASK);
const TransparencyMode old_transparency_mode = transparency_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)));
@ -808,7 +811,7 @@ void GPU::RenderState::SetFromPaletteAttribute(u16 value)
texture_palette_x = static_cast<s32>(ZeroExtend32(value & UINT16_C(0x3F)) * UINT32_C(16)); texture_palette_x = static_cast<s32>(ZeroExtend32(value & UINT16_C(0x3F)) * UINT32_C(16));
texture_palette_y = static_cast<s32>(ZeroExtend32((value >> 6) & UINT16_C(0x1FF))); texture_palette_y = static_cast<s32>(ZeroExtend32((value >> 6) & UINT16_C(0x1FF)));
texlut_attribute = value; texlut_attribute = value;
texture_changed = true; texture_page_changed = true;
} }
bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha) bool GPU::DumpVRAMToFile(const char* filename, u32 width, u32 height, u32 stride, const void* buffer, bool remove_alpha)

View File

@ -223,7 +223,7 @@ protected:
struct RenderState struct RenderState
{ {
static constexpr u16 PAGE_ATTRIBUTE_TEXTURE_MASK = UINT16_C(0b0000000110011111); static constexpr u16 PAGE_ATTRIBUTE_TEXTURE_PAGE_MASK = UINT16_C(0b0000000000011111);
static constexpr u16 PAGE_ATTRIBUTE_MASK = UINT16_C(0b0000000111111111); static constexpr u16 PAGE_ATTRIBUTE_MASK = UINT16_C(0b0000000111111111);
static constexpr u16 PALETTE_ATTRIBUTE_MASK = UINT16_C(0b0111111111111111); static constexpr u16 PALETTE_ATTRIBUTE_MASK = UINT16_C(0b0111111111111111);
@ -245,13 +245,17 @@ protected:
u16 texpage_attribute; // from register in rectangle modes/vertex in polygon modes u16 texpage_attribute; // from register in rectangle modes/vertex in polygon modes
u16 texlut_attribute; // from vertex u16 texlut_attribute; // from vertex
bool texture_changed = false; bool texture_page_changed = false;
bool texture_color_mode_changed = false;
bool transparency_mode_changed = false; bool transparency_mode_changed = false;
bool IsChanged() const { return texture_changed || transparency_mode_changed; } bool IsChanged() const { return texture_page_changed || texture_color_mode_changed || transparency_mode_changed; }
bool IsTextureChanged() const { return texture_changed; } bool IsTexturePageChanged() const { return texture_page_changed; }
void ClearTextureChangedFlag() { texture_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; } bool IsTransparencyModeChanged() const { return transparency_mode_changed; }
void ClearTransparencyModeChangedFlag() { transparency_mode_changed = false; } void ClearTransparencyModeChangedFlag() { transparency_mode_changed = false; }

View File

@ -10,6 +10,9 @@ GPU_HW::~GPU_HW() = default;
void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices) void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
{ {
const u32 texpage =
ZeroExtend32(m_render_state.texpage_attribute) | (ZeroExtend32(m_render_state.texlut_attribute) << 16);
// TODO: Move this to the GPU.. // TODO: Move this to the GPU..
switch (rc.primitive) switch (rc.primitive)
{ {
@ -33,6 +36,7 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
const VertexPosition vp{m_GP0_command[buffer_pos++]}; const VertexPosition vp{m_GP0_command[buffer_pos++]};
hw_vert.x = vp.x(); hw_vert.x = vp.x();
hw_vert.y = vp.y(); hw_vert.y = vp.y();
hw_vert.texpage = texpage;
if (textured) if (textured)
hw_vert.texcoord = Truncate16(m_GP0_command[buffer_pos++]); hw_vert.texcoord = Truncate16(m_GP0_command[buffer_pos++]);
@ -94,13 +98,16 @@ void GPU_HW::LoadVertices(RenderCommand rc, u32 num_vertices)
const u8 tex_right = static_cast<u8>(tex_left + (rectangle_width - 1)); const u8 tex_right = static_cast<u8>(tex_left + (rectangle_width - 1));
const u8 tex_bottom = static_cast<u8>(tex_top + (rectangle_height - 1)); const u8 tex_bottom = static_cast<u8>(tex_top + (rectangle_height - 1));
m_batch.vertices.push_back(HWVertex{pos_left, pos_top, color, HWVertex::EncodeTexcoord(tex_left, tex_top)}); m_batch.vertices.push_back(
HWVertex{pos_left, pos_top, color, texpage, HWVertex::EncodeTexcoord(tex_left, tex_top)});
if (restart_strip) if (restart_strip)
m_batch.vertices.push_back(m_batch.vertices.back()); m_batch.vertices.push_back(m_batch.vertices.back());
m_batch.vertices.push_back(HWVertex{pos_right, pos_top, color, HWVertex::EncodeTexcoord(tex_right, tex_top)});
m_batch.vertices.push_back(HWVertex{pos_left, pos_bottom, color, HWVertex::EncodeTexcoord(tex_left, tex_bottom)});
m_batch.vertices.push_back( m_batch.vertices.push_back(
HWVertex{pos_right, pos_bottom, color, HWVertex::EncodeTexcoord(tex_right, tex_bottom)}); HWVertex{pos_right, pos_top, color, texpage, HWVertex::EncodeTexcoord(tex_right, tex_top)});
m_batch.vertices.push_back(
HWVertex{pos_left, pos_bottom, color, texpage, HWVertex::EncodeTexcoord(tex_left, tex_bottom)});
m_batch.vertices.push_back(
HWVertex{pos_right, pos_bottom, color, texpage, HWVertex::EncodeTexcoord(tex_right, tex_bottom)});
} }
break; break;
@ -175,10 +182,12 @@ std::string GPU_HW::GenerateVertexShader(bool textured)
in ivec2 a_pos; in ivec2 a_pos;
in vec4 a_col0; in vec4 a_col0;
in vec2 a_tex0; in vec2 a_tex0;
in int a_texpage;
out vec3 v_col0; out vec3 v_col0;
#if TEXTURED #if TEXTURED
out vec2 v_tex0; out vec2 v_tex0;
flat out ivec4 v_texpage;
#endif #endif
uniform ivec2 u_pos_offset; uniform ivec2 u_pos_offset;
@ -193,6 +202,12 @@ void main()
v_col0 = a_col0.rgb; v_col0 = a_col0.rgb;
#if TEXTURED #if TEXTURED
v_tex0 = a_tex0; v_tex0 = a_tex0;
// base_x,base_y,palette_x,palette_y
v_texpage.x = (a_texpage & 15) * 64;
v_texpage.y = ((a_texpage >> 4) & 1) * 256;
v_texpage.z = ((a_texpage >> 16) & 63) * 16;
v_texpage.w = ((a_texpage >> 22) & 511);
#endif #endif
} }
)"; )";
@ -218,11 +233,8 @@ in vec3 v_col0;
uniform vec2 u_transparent_alpha; uniform vec2 u_transparent_alpha;
#if TEXTURED #if TEXTURED
in vec2 v_tex0; in vec2 v_tex0;
flat in ivec4 v_texpage;
uniform sampler2D samp0; uniform sampler2D samp0;
uniform ivec2 u_texture_page_base;
#if PALETTE
uniform ivec2 u_texture_palette_base;
#endif
#endif #endif
out vec4 o_col0; out vec4 o_col0;
@ -242,8 +254,8 @@ vec4 SampleFromVRAM(vec2 coord)
#endif #endif
// fixup coords // fixup coords
ivec2 vicoord = ivec2(u_texture_page_base.x + index_coord.x, ivec2 vicoord = ivec2(v_texpage.x + index_coord.x,
fixYCoord(u_texture_page_base.y + index_coord.y)); fixYCoord(v_texpage.y + index_coord.y));
// load colour/palette // load colour/palette
vec4 color = texelFetch(samp0, vicoord & VRAM_COORD_MASK, 0); vec4 color = texelFetch(samp0, vicoord & VRAM_COORD_MASK, 0);
@ -259,7 +271,7 @@ vec4 SampleFromVRAM(vec2 coord)
uint vram_value = RGBA8ToRGBA5551(color); uint vram_value = RGBA8ToRGBA5551(color);
int palette_index = int((vram_value >> (subpixel * 8)) & 0xFFu); int palette_index = int((vram_value >> (subpixel * 8)) & 0xFFu);
#endif #endif
ivec2 palette_icoord = ivec2(u_texture_palette_base.x + palette_index, fixYCoord(u_texture_palette_base.y)); ivec2 palette_icoord = ivec2(v_texpage.z + palette_index, fixYCoord(v_texpage.w));
color = texelFetch(samp0, palette_icoord & VRAM_COORD_MASK, 0); color = texelFetch(samp0, palette_icoord & VRAM_COORD_MASK, 0);
#endif #endif
@ -393,7 +405,9 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
m_batch.render_command_bits != rc.bits && m_batch.transparency_enable != rc_transparency_enable || m_batch.render_command_bits != rc.bits && m_batch.transparency_enable != rc_transparency_enable ||
m_batch.texture_enable != rc_texture_enable || m_batch.texture_blending_enable != rc_texture_blend_enable || m_batch.texture_enable != rc_texture_enable || m_batch.texture_blending_enable != rc_texture_blend_enable ||
m_batch.primitive != rc_primitive; m_batch.primitive != rc_primitive;
const bool needs_flush = !IsFlushed() && (m_render_state.IsChanged() || buffer_overflow || rc_changed); const bool needs_flush =
!IsFlushed() && (m_render_state.IsTextureColorModeChanged() || m_render_state.IsTransparencyModeChanged() ||
buffer_overflow || rc_changed);
if (needs_flush) if (needs_flush)
FlushRender(); FlushRender();
@ -407,7 +421,7 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
m_batch.texture_blending_enable = rc_texture_blend_enable; m_batch.texture_blending_enable = rc_texture_blend_enable;
} }
if (m_render_state.IsTextureChanged()) if (m_render_state.IsTexturePageChanged())
{ {
// we only need to update the copy texture if the render area intersects with the texture page // we only need to update the copy texture if the render area intersects with the texture page
const u32 texture_page_left = m_render_state.texture_page_x; const u32 texture_page_left = m_render_state.texture_page_x;
@ -425,12 +439,17 @@ void GPU_HW::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
InvalidateVRAMReadCache(); InvalidateVRAMReadCache();
} }
m_batch.texture_color_mode = m_render_state.texture_color_mode;
m_batch.texture_page_x = m_render_state.texture_page_x; m_batch.texture_page_x = m_render_state.texture_page_x;
m_batch.texture_page_y = m_render_state.texture_page_y; m_batch.texture_page_y = m_render_state.texture_page_y;
m_batch.texture_palette_x = m_render_state.texture_palette_x; m_batch.texture_palette_x = m_render_state.texture_palette_x;
m_batch.texture_palette_y = m_render_state.texture_palette_y; m_batch.texture_palette_y = m_render_state.texture_palette_y;
m_render_state.ClearTextureChangedFlag(); 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()) if (m_render_state.IsTransparencyModeChanged())

View File

@ -16,9 +16,9 @@ protected:
s32 x; s32 x;
s32 y; s32 y;
u32 color; u32 color;
u32 texpage;
u16 texcoord; u16 texcoord;
u16 padding; u16 padding;
u32 texpage;
static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord) static constexpr std::tuple<u8, u8> DecodeTexcoord(u16 texcoord)
{ {

View File

@ -138,11 +138,13 @@ void GPU_HW_OpenGL::CreateVertexBuffer()
glEnableVertexAttribArray(0); glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1); glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2); glEnableVertexAttribArray(2);
glEnableVertexAttribArray(3);
glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x))); glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x)));
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex), glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
reinterpret_cast<void*>(offsetof(HWVertex, color))); reinterpret_cast<void*>(offsetof(HWVertex, color)));
glVertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, true, sizeof(HWVertex), glVertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
reinterpret_cast<void*>(offsetof(HWVertex, texcoord))); reinterpret_cast<void*>(offsetof(HWVertex, texcoord)));
glVertexAttribIPointer(3, 1, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, texpage)));
glBindVertexArray(0); glBindVertexArray(0);
glGenVertexArrays(1, &m_attributeless_vao_id); glGenVertexArrays(1, &m_attributeless_vao_id);
@ -184,7 +186,10 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blendi
prog.BindAttribute(0, "a_pos"); prog.BindAttribute(0, "a_pos");
prog.BindAttribute(1, "a_col0"); prog.BindAttribute(1, "a_col0");
if (textured) if (textured)
{
prog.BindAttribute(2, "a_tex0"); prog.BindAttribute(2, "a_tex0");
prog.BindAttribute(3, "a_texpage");
}
prog.BindFragData(0, "o_col0"); prog.BindFragData(0, "o_col0");
@ -200,8 +205,6 @@ bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blendi
if (textured) if (textured)
{ {
prog.RegisterUniform("samp0"); prog.RegisterUniform("samp0");
prog.RegisterUniform("u_texture_page_base");
prog.RegisterUniform("u_texture_palette_base");
prog.Uniform1i(2, 0); prog.Uniform1i(2, 0);
} }
@ -228,11 +231,7 @@ void GPU_HW_OpenGL::SetProgram()
} }
if (m_batch.texture_enable) if (m_batch.texture_enable)
{
m_vram_read_texture->Bind(); m_vram_read_texture->Bind();
prog.Uniform2i(3, m_batch.texture_page_x, m_batch.texture_page_y);
prog.Uniform2i(4, m_batch.texture_palette_x, m_batch.texture_palette_y);
}
} }
void GPU_HW_OpenGL::SetViewport() void GPU_HW_OpenGL::SetViewport()