GPU: Partially implemented texture support
This commit is contained in:
@ -32,6 +32,11 @@ void GPU_HW_OpenGL::Reset()
|
||||
ClearFramebuffer();
|
||||
}
|
||||
|
||||
std::tuple<s32, s32> GPU_HW_OpenGL::ConvertToFramebufferCoordinates(s32 x, s32 y)
|
||||
{
|
||||
return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y));
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::CreateFramebuffer()
|
||||
{
|
||||
m_framebuffer_texture =
|
||||
@ -41,6 +46,13 @@ void GPU_HW_OpenGL::CreateFramebuffer()
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_framebuffer_texture->GetGLId(), 0);
|
||||
Assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
|
||||
m_texture_page_texture =
|
||||
std::make_unique<GL::Texture>(TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false);
|
||||
glGenFramebuffers(1, &m_texture_page_fbo_id);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_texture_page_fbo_id);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_texture_page_texture->GetGLId(), 0);
|
||||
Assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::ClearFramebuffer()
|
||||
@ -51,14 +63,17 @@ void GPU_HW_OpenGL::ClearFramebuffer()
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
//m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||
m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::DestroyFramebuffer()
|
||||
{
|
||||
glDeleteFramebuffers(1, &m_texture_page_fbo_id);
|
||||
m_texture_page_fbo_id = 0;
|
||||
m_texture_page_texture.reset();
|
||||
|
||||
glDeleteFramebuffers(1, &m_framebuffer_fbo_id);
|
||||
m_framebuffer_fbo_id = 0;
|
||||
|
||||
m_framebuffer_texture.reset();
|
||||
}
|
||||
|
||||
@ -70,52 +85,86 @@ void GPU_HW_OpenGL::CreateVertexBuffer()
|
||||
|
||||
glGenVertexArrays(1, &m_vao_id);
|
||||
glBindVertexArray(m_vao_id);
|
||||
glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x)));
|
||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||
reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||
glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||
glEnableVertexAttribArray(0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x)));
|
||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||
reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||
glVertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||
reinterpret_cast<void*>(offsetof(HWVertex, texcoord)));
|
||||
glBindVertexArray(0);
|
||||
|
||||
glGenVertexArrays(1, &m_attributeless_vao_id);
|
||||
}
|
||||
|
||||
bool GPU_HW_OpenGL::CompilePrograms()
|
||||
{
|
||||
for (u32 texture_enable_i = 0; texture_enable_i < 2; texture_enable_i++)
|
||||
{
|
||||
const bool texture_enable = ConvertToBool(texture_enable_i);
|
||||
const std::string vs = GenerateVertexShader(texture_enable);
|
||||
const std::string fs = GenerateFragmentShader(texture_enable);
|
||||
bool result = true;
|
||||
result &= CompileProgram(m_color_program, false, false);
|
||||
result &= CompileProgram(m_texture_program, true, false);
|
||||
result &= CompileProgram(m_blended_texture_program, true, true);
|
||||
if (!result)
|
||||
return false;
|
||||
|
||||
GL::Program& prog = texture_enable ? m_texture_program : m_color_program;
|
||||
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
||||
const std::string screen_quad_vs = GenerateScreenQuadVertexShader();
|
||||
for (u32 palette_size = 0; palette_size < static_cast<u32>(m_texture_page_programs.size()); palette_size++)
|
||||
{
|
||||
const std::string fs = GenerateTexturePageProgram(static_cast<TextureColorMode>(palette_size));
|
||||
|
||||
GL::Program& prog = m_texture_page_programs[palette_size];
|
||||
if (!prog.Compile(screen_quad_vs.c_str(), fs.c_str()))
|
||||
return false;
|
||||
|
||||
prog.BindAttribute(0, "a_position");
|
||||
prog.BindAttribute(1, "a_color");
|
||||
if (texture_enable)
|
||||
prog.BindAttribute(2, "a_texcoord");
|
||||
|
||||
prog.BindFragData(0, "ocol0");
|
||||
prog.BindFragData(0, "o_col0");
|
||||
|
||||
if (!prog.Link())
|
||||
return false;
|
||||
|
||||
prog.RegisterUniform("samp0");
|
||||
prog.RegisterUniform("base_offset");
|
||||
prog.RegisterUniform("palette_offset");
|
||||
prog.Bind();
|
||||
prog.Uniform1i(0, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPU_HW_OpenGL::SetProgram(bool texture_enable)
|
||||
bool GPU_HW_OpenGL::CompileProgram(GL::Program& prog, bool textured, bool blending)
|
||||
{
|
||||
GL::Program& prog = texture_enable ? m_texture_program : m_color_program;
|
||||
if (!prog.IsVaild())
|
||||
const std::string vs = GenerateVertexShader(textured);
|
||||
const std::string fs = GenerateFragmentShader(textured, blending);
|
||||
if (!prog.Compile(vs.c_str(), fs.c_str()))
|
||||
return false;
|
||||
|
||||
prog.BindAttribute(0, "a_pos");
|
||||
prog.BindAttribute(1, "a_col0");
|
||||
if (textured)
|
||||
prog.BindAttribute(2, "a_tex0");
|
||||
|
||||
prog.BindFragData(0, "o_col0");
|
||||
|
||||
if (!prog.Link())
|
||||
return false;
|
||||
|
||||
prog.Bind();
|
||||
|
||||
if (textured)
|
||||
{
|
||||
prog.RegisterUniform("samp0");
|
||||
prog.Uniform1i(0, 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::SetProgram(bool textured, bool blending)
|
||||
{
|
||||
const GL::Program& prog = textured ? (blending ? m_blended_texture_program : m_texture_program) : m_color_program;
|
||||
prog.Bind();
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::SetViewport()
|
||||
{
|
||||
int x, y, width, height;
|
||||
@ -144,70 +193,100 @@ inline u32 ConvertRGBA5551ToRGBA8888(u16 color)
|
||||
return ZeroExtend32(r) | (ZeroExtend32(g) << 8) | (ZeroExtend32(b) << 16) | (ZeroExtend32(a) << 24);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
||||
void GPU_HW_OpenGL::UpdateDisplay()
|
||||
{
|
||||
const u32 pixel_count = width * height;
|
||||
std::vector<u32> rgba_data;
|
||||
rgba_data.reserve(pixel_count);
|
||||
|
||||
const u8* source_ptr = static_cast<const u8*>(data);
|
||||
for (u32 i = 0; i < pixel_count; i++)
|
||||
{
|
||||
u16 src_col;
|
||||
std::memcpy(&src_col, source_ptr, sizeof(src_col));
|
||||
source_ptr += sizeof(src_col);
|
||||
|
||||
const u32 dst_col = ConvertRGBA5551ToRGBA8888(src_col);
|
||||
rgba_data.push_back(dst_col);
|
||||
}
|
||||
|
||||
m_framebuffer_texture->Bind();
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
rgba_data.data());
|
||||
GPU_HW::UpdateDisplay();
|
||||
m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::DispatchRenderCommand(RenderCommand rc, u32 num_vertices)
|
||||
void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void* data)
|
||||
{
|
||||
LoadVertices(rc, num_vertices);
|
||||
if (m_vertex_staging.empty())
|
||||
return;
|
||||
std::vector<u32> rgba_data;
|
||||
rgba_data.reserve(width * height);
|
||||
|
||||
if (!SetProgram(rc.texture_enable))
|
||||
// reverse copy the rows so it matches opengl's lower-left origin
|
||||
const u32 source_stride = width * sizeof(u16);
|
||||
const u8* source_ptr = static_cast<const u8*>(data) + (source_stride * (height - 1));
|
||||
for (u32 row = 0; row < height; row++)
|
||||
{
|
||||
Log_ErrorPrintf("Failed to set GL program");
|
||||
m_vertex_staging.clear();
|
||||
return;
|
||||
const u8* source_row_ptr = source_ptr;
|
||||
|
||||
for (u32 col = 0; col < width; col++)
|
||||
{
|
||||
u16 src_col;
|
||||
std::memcpy(&src_col, source_row_ptr, sizeof(src_col));
|
||||
source_row_ptr += sizeof(src_col);
|
||||
|
||||
const u32 dst_col = ConvertRGBA5551ToRGBA8888(src_col);
|
||||
rgba_data.push_back(dst_col);
|
||||
}
|
||||
|
||||
source_ptr -= source_stride;
|
||||
}
|
||||
|
||||
m_framebuffer_texture->Bind();
|
||||
|
||||
// lower-left origin flip happens here
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, x, VRAM_HEIGHT - y - height, width, height, GL_RGBA, GL_UNSIGNED_BYTE,
|
||||
rgba_data.data());
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::UpdateTexturePageTexture()
|
||||
{
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_texture_page_fbo_id);
|
||||
m_framebuffer_texture->Bind();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glViewport(0, 0, TEXTURE_PAGE_WIDTH, TEXTURE_PAGE_HEIGHT);
|
||||
glBindVertexArray(m_attributeless_vao_id);
|
||||
|
||||
const GL::Program& prog = m_texture_page_programs[static_cast<u8>(m_texture_config.color_mode)];
|
||||
prog.Bind();
|
||||
|
||||
const float base_x = static_cast<float>(m_texture_config.base_x) * (1.0f / static_cast<float>(VRAM_WIDTH));
|
||||
const float base_y = static_cast<float>(m_texture_config.base_y) * (1.0f / static_cast<float>(VRAM_HEIGHT));
|
||||
prog.Uniform2f(1, base_x, base_y);
|
||||
|
||||
if (m_texture_config.color_mode >= GPU::TextureColorMode::Palette4Bit)
|
||||
{
|
||||
const float palette_x = static_cast<float>(m_texture_config.palette_x) * (1.0f / static_cast<float>(VRAM_WIDTH));
|
||||
const float palette_y = static_cast<float>(m_texture_config.palette_y) * (1.0f / static_cast<float>(VRAM_HEIGHT));
|
||||
prog.Uniform2f(2, palette_x, palette_y);
|
||||
}
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 3);
|
||||
|
||||
m_framebuffer_texture->Unbind();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::FlushRender()
|
||||
{
|
||||
if (m_batch_vertices.empty())
|
||||
return;
|
||||
|
||||
SetProgram(m_batch_command.texture_enable, m_batch_command.texture_blending_raw);
|
||||
SetViewport();
|
||||
|
||||
if (m_batch_command.texture_enable)
|
||||
m_texture_page_texture->Bind();
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer_fbo_id);
|
||||
glBindVertexArray(m_vao_id);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, m_vertex_buffer);
|
||||
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(HWVertex) * m_vertex_staging.size()),
|
||||
m_vertex_staging.data(), GL_STREAM_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizei>(sizeof(HWVertex) * m_batch_vertices.size()),
|
||||
m_batch_vertices.data(), GL_STREAM_DRAW);
|
||||
glVertexAttribIPointer(0, 2, GL_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, x)));
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||
reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||
glEnableVertexAttribArray(2);
|
||||
glVertexAttribIPointer(2, 1, GL_UNSIGNED_INT, sizeof(HWVertex), reinterpret_cast<void*>(offsetof(HWVertex, color)));
|
||||
glVertexAttribPointer(2, 2, GL_UNSIGNED_BYTE, true, sizeof(HWVertex),
|
||||
reinterpret_cast<void*>(offsetof(HWVertex, texcoord)));
|
||||
|
||||
glDrawArrays(rc.quad_polygon ? GL_TRIANGLE_STRIP : GL_TRIANGLES, 0, static_cast<GLsizei>(m_vertex_staging.size()));
|
||||
glDrawArrays(m_batch_command.quad_polygon ? GL_TRIANGLE_STRIP : GL_TRIANGLES, 0,
|
||||
static_cast<GLsizei>(m_batch_vertices.size()));
|
||||
|
||||
m_system->GetHostInterface()->SetDisplayTexture(m_framebuffer_texture.get(), 0, 0, VRAM_WIDTH, VRAM_HEIGHT);
|
||||
m_vertex_staging.clear();
|
||||
}
|
||||
|
||||
void GPU_HW_OpenGL::FlushRender()
|
||||
{
|
||||
if (m_vertex_staging.empty())
|
||||
return;
|
||||
|
||||
m_vertex_staging.clear();
|
||||
m_batch_vertices.clear();
|
||||
}
|
||||
|
||||
std::unique_ptr<GPU> GPU::CreateHardwareOpenGLRenderer()
|
||||
|
||||
Reference in New Issue
Block a user