GL: Improve error handling with texture creation

This commit is contained in:
Connor McLaughlin 2019-12-11 00:01:29 +10:00
parent 05e6d4c401
commit 6f78fea159
8 changed files with 328 additions and 213 deletions

View File

@ -5,32 +5,96 @@ Log_SetChannel(GL);
namespace GL { namespace GL {
Texture::Texture(u32 width, u32 height, GLenum format, GLenum type, const void* data /* = nullptr */, Texture::Texture() = default;
bool linear_filter /* = false */, bool create_framebuffer /* = false */)
: m_width(width), m_height(height) Texture::Texture(Texture&& moved)
: m_id(moved.m_id), m_width(moved.m_width), m_height(moved.m_height), m_fbo_id(moved.m_fbo_id)
{ {
glGenTextures(1, &m_id); moved.m_id = 0;
glBindTexture(GL_TEXTURE_2D, m_id); moved.m_width = 0;
moved.m_height = 0;
moved.m_fbo_id = 0;
}
Texture::~Texture()
{
Destroy();
}
bool Texture::Create(u32 width, u32 height, GLenum format, GLenum type, const void* data, bool linear_filter)
{
glGetError();
GLuint id;
glGenTextures(1, &id);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linear_filter ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 1);
if (create_framebuffer) if (glGetError() != GL_NO_ERROR)
{ {
glGenFramebuffers(1, &m_fbo_id); glDeleteTextures(1, &id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_id); return false;
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_id, 0);
Assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
}
} }
Texture::~Texture() if (IsValid())
Destroy();
m_id = id;
m_width = width;
m_height = height;
return true;
}
void Texture::SetLinearFilter(bool enabled)
{ {
Bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, enabled ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, enabled ? GL_LINEAR : GL_NEAREST);
}
bool Texture::CreateFramebuffer()
{
if (!IsValid())
return false;
glGetError();
GLuint fbo_id;
glGenFramebuffers(1, &fbo_id);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_id);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_id, 0);
if (glGetError() != GL_NO_ERROR || glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
{
glDeleteFramebuffers(1, &fbo_id);
return false;
}
if (m_fbo_id != 0) if (m_fbo_id != 0)
glDeleteFramebuffers(1, &m_fbo_id); glDeleteFramebuffers(1, &m_fbo_id);
m_fbo_id = fbo_id;
return true;
}
void Texture::Destroy()
{
if (m_fbo_id != 0)
{
glDeleteFramebuffers(1, &m_fbo_id);
m_fbo_id = 0;
}
if (m_id != 0)
{
glDeleteTextures(1, &m_id); glDeleteTextures(1, &m_id);
m_id = 0;
}
m_width = 0;
m_height = 0;
} }
void Texture::Bind() void Texture::Bind()
@ -49,4 +113,20 @@ void Texture::Unbind()
glBindTexture(GL_TEXTURE_2D, 0); glBindTexture(GL_TEXTURE_2D, 0);
} }
Texture& Texture::operator=(Texture&& moved)
{
Destroy();
m_id = moved.m_id;
m_width = moved.m_width;
m_height = moved.m_height;
m_fbo_id = moved.m_fbo_id;
moved.m_id = 0;
moved.m_width = 0;
moved.m_height = 0;
moved.m_fbo_id = 0;
return *this;
}
} // namespace GL } // namespace GL

View File

@ -1,15 +1,24 @@
#pragma once #pragma once
#include <glad.h>
#include "../types.h" #include "../types.h"
#include <glad.h>
namespace GL { namespace GL {
class Texture class Texture
{ {
public: public:
Texture(u32 width, u32 height, GLenum format, GLenum type, const void* data = nullptr, bool linear_filter = false, Texture();
bool create_framebuffer = false); Texture(Texture&& moved);
~Texture(); ~Texture();
bool Create(u32 width, u32 height, GLenum format, GLenum type, const void* data = nullptr,
bool linear_filter = false);
bool CreateFramebuffer();
void Destroy();
void SetLinearFilter(bool enabled);
bool IsValid() const { return m_id != 0; }
GLuint GetGLId() const { return m_id; } GLuint GetGLId() const { return m_id; }
u32 GetWidth() const { return m_width; } u32 GetWidth() const { return m_width; }
u32 GetHeight() const { return m_height; } u32 GetHeight() const { return m_height; }
@ -21,10 +30,14 @@ public:
static void Unbind(); static void Unbind();
Texture& operator=(const Texture& copy) = delete;
Texture& operator=(Texture&& moved);
private: private:
GLuint m_id;
u32 m_width; GLuint m_id = 0;
u32 m_height; u32 m_width = 0;
u32 m_height = 0;
GLuint m_fbo_id = 0; GLuint m_fbo_id = 0;
}; };

View File

@ -41,16 +41,39 @@ bool GPU_HW_OpenGL::Initialize(HostDisplay* host_display, System* system, DMA* d
if (!GPU_HW::Initialize(host_display, system, dma, interrupt_controller, timers)) if (!GPU_HW::Initialize(host_display, system, dma, interrupt_controller, timers))
return false; return false;
CreateFramebuffer(); if (!CreateFramebuffer())
CreateVertexBuffer(); {
CreateUniformBuffer(); Log_ErrorPrintf("Failed to create framebuffer");
CreateTextureBuffer();
if (!CompilePrograms())
return false; return false;
}
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), 0, 0, if (!CreateVertexBuffer())
m_display_texture->GetWidth(), m_display_texture->GetHeight(), {
m_display_texture->GetWidth(), m_display_texture->GetHeight(), 1.0f); Log_ErrorPrintf("Failed to create vertex buffer");
return false;
}
if (!CreateUniformBuffer())
{
Log_ErrorPrintf("Failed to create uniform buffer");
return false;
}
if (!CreateTextureBuffer())
{
Log_ErrorPrintf("Failed to create texture buffer");
return false;
}
if (!CompilePrograms())
{
Log_ErrorPrintf("Failed to compile programs");
return false;
}
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), 0, 0,
m_display_texture.GetWidth(), m_display_texture.GetHeight(),
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 1.0f);
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
return true; return true;
} }
@ -76,8 +99,8 @@ void GPU_HW_OpenGL::ResetGraphicsAPIState()
void GPU_HW_OpenGL::RestoreGraphicsAPIState() void GPU_HW_OpenGL::RestoreGraphicsAPIState()
{ {
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); glViewport(0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -162,47 +185,50 @@ void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display)
Log_WarningPrintf("Dual-source blending is not supported, this may break some mask effects."); Log_WarningPrintf("Dual-source blending is not supported, this may break some mask effects.");
} }
void GPU_HW_OpenGL::CreateFramebuffer() bool GPU_HW_OpenGL::CreateFramebuffer()
{ {
// save old vram texture/fbo, in case we're changing scale // save old vram texture/fbo, in case we're changing scale
auto old_vram_texture = std::move(m_vram_texture); GL::Texture old_vram_texture = std::move(m_vram_texture);
DestroyFramebuffer();
// scale vram size to internal resolution // scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale; const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
const u32 texture_height = VRAM_HEIGHT * m_resolution_scale; const u32 texture_height = VRAM_HEIGHT * m_resolution_scale;
m_vram_texture = if (!m_vram_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); !m_vram_texture.CreateFramebuffer())
// do we need to restore the framebuffer after a size change?
if (old_vram_texture)
{ {
const bool linear_filter = old_vram_texture->GetWidth() > m_vram_texture->GetWidth(); return false;
Log_DevPrintf("Scaling %ux%u VRAM texture to %ux%u using %s filter", old_vram_texture->GetWidth(),
old_vram_texture->GetHeight(), m_vram_texture->GetWidth(), m_vram_texture->GetHeight(),
linear_filter ? "linear" : "nearest");
glDisable(GL_SCISSOR_TEST);
old_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(0, 0, old_vram_texture->GetWidth(), old_vram_texture->GetHeight(), 0, 0,
m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), GL_COLOR_BUFFER_BIT,
linear_filter ? GL_LINEAR : GL_NEAREST);
glEnable(GL_SCISSOR_TEST);
old_vram_texture.reset();
} }
m_vram_read_texture = // do we need to restore the framebuffer after a size change?
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); if (old_vram_texture.IsValid())
{
const bool linear_filter = old_vram_texture.GetWidth() > m_vram_texture.GetWidth();
Log_DevPrintf("Scaling %ux%u VRAM texture to %ux%u using %s filter", old_vram_texture.GetWidth(),
old_vram_texture.GetHeight(), m_vram_texture.GetWidth(), m_vram_texture.GetHeight(),
linear_filter ? "linear" : "nearest");
glDisable(GL_SCISSOR_TEST);
old_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(0, 0, old_vram_texture.GetWidth(), old_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), GL_COLOR_BUFFER_BIT, linear_filter ? GL_LINEAR : GL_NEAREST);
m_vram_encoding_texture = glEnable(GL_SCISSOR_TEST);
std::make_unique<GL::Texture>(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); old_vram_texture.Destroy();
}
m_display_texture = if (!m_vram_read_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); !m_vram_read_texture.CreateFramebuffer() ||
!m_vram_encoding_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
!m_vram_encoding_texture.CreateFramebuffer() ||
!m_display_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
!m_display_texture.CreateFramebuffer())
{
return false;
}
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
SetFullVRAMDirtyRectangle(); SetFullVRAMDirtyRectangle();
return true;
} }
void GPU_HW_OpenGL::ClearFramebuffer() void GPU_HW_OpenGL::ClearFramebuffer()
@ -214,19 +240,11 @@ void GPU_HW_OpenGL::ClearFramebuffer()
SetFullVRAMDirtyRectangle(); SetFullVRAMDirtyRectangle();
} }
void GPU_HW_OpenGL::DestroyFramebuffer() bool GPU_HW_OpenGL::CreateVertexBuffer()
{
m_vram_read_texture.reset();
m_vram_texture.reset();
m_vram_encoding_texture.reset();
m_display_texture.reset();
}
void GPU_HW_OpenGL::CreateVertexBuffer()
{ {
m_vertex_stream_buffer = GL::StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE); m_vertex_stream_buffer = GL::StreamBuffer::Create(GL_ARRAY_BUFFER, VERTEX_BUFFER_SIZE);
if (!m_vertex_stream_buffer) if (!m_vertex_stream_buffer)
Panic("Failed to create vertex streaming buffer"); return false;
m_vertex_stream_buffer->Bind(); m_vertex_stream_buffer->Bind();
@ -244,21 +262,24 @@ void GPU_HW_OpenGL::CreateVertexBuffer()
glBindVertexArray(0); glBindVertexArray(0);
glGenVertexArrays(1, &m_attributeless_vao_id); glGenVertexArrays(1, &m_attributeless_vao_id);
return true;
} }
void GPU_HW_OpenGL::CreateUniformBuffer() bool GPU_HW_OpenGL::CreateUniformBuffer()
{ {
m_uniform_stream_buffer = GL::StreamBuffer::Create(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE); m_uniform_stream_buffer = GL::StreamBuffer::Create(GL_UNIFORM_BUFFER, UNIFORM_BUFFER_SIZE);
if (!m_uniform_stream_buffer) if (!m_uniform_stream_buffer)
Panic("Failed to create uniform buffer"); return false;
return true;
} }
void GPU_HW_OpenGL::CreateTextureBuffer() bool GPU_HW_OpenGL::CreateTextureBuffer()
{ {
// We use the pixel unpack buffer here because we share it with CPU-decoded VRAM writes. // We use the pixel unpack buffer here because we share it with CPU-decoded VRAM writes.
m_texture_stream_buffer = GL::StreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, VRAM_UPDATE_TEXTURE_BUFFER_SIZE); m_texture_stream_buffer = GL::StreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, VRAM_UPDATE_TEXTURE_BUFFER_SIZE);
if (!m_texture_stream_buffer) if (!m_texture_stream_buffer)
Panic("Failed to create texture stream buffer"); return false;
if (m_max_texture_buffer_size > 0) if (m_max_texture_buffer_size > 0)
{ {
@ -268,6 +289,7 @@ void GPU_HW_OpenGL::CreateTextureBuffer()
} }
m_texture_stream_buffer->Unbind(); m_texture_stream_buffer->Unbind();
return true;
} }
bool GPU_HW_OpenGL::CompilePrograms() bool GPU_HW_OpenGL::CompilePrograms()
@ -396,7 +418,7 @@ void GPU_HW_OpenGL::SetDrawState(BatchRenderMode render_mode)
prog.Bind(); prog.Bind();
if (m_batch.texture_mode != TextureMode::Disabled) if (m_batch.texture_mode != TextureMode::Disabled)
m_vram_read_texture->Bind(); m_vram_read_texture.Bind();
if (m_batch.transparency_mode == TransparencyMode::Disabled || render_mode == BatchRenderMode::OnlyOpaque) if (m_batch.transparency_mode == TransparencyMode::Disabled || render_mode == BatchRenderMode::OnlyOpaque)
{ {
@ -433,7 +455,7 @@ void GPU_HW_OpenGL::SetScissorFromDrawingArea()
const int width = right - left; const int width = right - left;
const int height = bottom - top; const int height = bottom - top;
const int x = left; const int x = left;
const int y = m_vram_texture->GetHeight() - bottom; const int y = m_vram_texture.GetHeight() - bottom;
Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height); Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height);
glScissor(x, y, width, height); glScissor(x, y, width, height);
@ -456,10 +478,10 @@ void GPU_HW_OpenGL::UpdateDisplay()
if (m_system->GetSettings().debugging.show_vram) if (m_system->GetSettings().debugging.show_vram)
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), 0, m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), 0,
m_vram_texture->GetHeight(), m_vram_texture->GetWidth(), m_vram_texture.GetHeight(), m_vram_texture.GetWidth(),
-static_cast<s32>(m_vram_texture->GetHeight()), m_vram_texture->GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight()), m_vram_texture.GetWidth(),
m_vram_texture->GetHeight(), 1.0f); m_vram_texture.GetHeight(), 1.0f);
} }
else else
{ {
@ -479,17 +501,17 @@ void GPU_HW_OpenGL::UpdateDisplay()
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && !interlaced) else if (!m_GPUSTAT.display_area_color_depth_24 && !interlaced)
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
scaled_vram_offset_x, m_vram_texture->GetHeight() - scaled_vram_offset_y, scaled_vram_offset_x, m_vram_texture.GetHeight() - scaled_vram_offset_y,
scaled_display_width, -static_cast<s32>(scaled_display_height), scaled_display_width, -static_cast<s32>(scaled_display_height),
m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), m_vram_texture.GetWidth(), m_vram_texture.GetHeight(),
m_crtc_state.display_aspect_ratio); m_crtc_state.display_aspect_ratio);
} }
else else
{ {
const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height; const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height;
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 field_offset = BoolToUInt8(interlaced && m_GPUSTAT.interlaced_field); const u32 field_offset = BoolToUInt8(interlaced && m_GPUSTAT.interlaced_field);
glDisable(GL_BLEND); glDisable(GL_BLEND);
@ -504,15 +526,15 @@ void GPU_HW_OpenGL::UpdateDisplay()
{ {
const u32 copy_width = std::min<u32>((display_width * 3) / 2, VRAM_WIDTH - vram_offset_x); const u32 copy_width = std::min<u32>((display_width * 3) / 2, VRAM_WIDTH - vram_offset_x);
const u32 scaled_copy_width = copy_width * m_resolution_scale; const u32 scaled_copy_width = copy_width * m_resolution_scale;
m_vram_encoding_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(scaled_vram_offset_x, scaled_flipped_vram_offset_y, scaled_vram_offset_x + scaled_copy_width, glBlitFramebuffer(scaled_vram_offset_x, scaled_flipped_vram_offset_y, scaled_vram_offset_x + scaled_copy_width,
scaled_flipped_vram_offset_y + scaled_display_height, vram_offset_x, flipped_vram_offset_y, scaled_flipped_vram_offset_y + scaled_display_height, vram_offset_x, flipped_vram_offset_y,
vram_offset_x + copy_width, flipped_vram_offset_y + display_height, GL_COLOR_BUFFER_BIT, vram_offset_x + copy_width, flipped_vram_offset_y + display_height, GL_COLOR_BUFFER_BIT,
GL_NEAREST); GL_NEAREST);
m_display_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_encoding_texture->Bind(); m_vram_encoding_texture.Bind();
glViewport(0, field_offset, display_width, display_height); glViewport(0, field_offset, display_width, display_height);
@ -522,15 +544,15 @@ void GPU_HW_OpenGL::UpdateDisplay()
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
0, display_height, display_width, -static_cast<s32>(display_height), 0, display_height, display_width, -static_cast<s32>(display_height),
m_display_texture->GetWidth(), m_display_texture->GetHeight(), m_display_texture.GetWidth(), m_display_texture.GetHeight(),
m_crtc_state.display_aspect_ratio); m_crtc_state.display_aspect_ratio);
} }
else else
{ {
m_display_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->Bind(); m_vram_texture.Bind();
glViewport(0, field_offset, scaled_display_width, scaled_display_height); glViewport(0, field_offset, scaled_display_width, scaled_display_height);
@ -540,15 +562,15 @@ void GPU_HW_OpenGL::UpdateDisplay()
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
0, scaled_display_height, scaled_display_width, 0, scaled_display_height, scaled_display_width,
-static_cast<s32>(scaled_display_height), m_display_texture->GetWidth(), -static_cast<s32>(scaled_display_height), m_display_texture.GetWidth(),
m_display_texture->GetHeight(), m_crtc_state.display_aspect_ratio); m_display_texture.GetHeight(), m_crtc_state.display_aspect_ratio);
} }
// restore state // restore state
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); glViewport(0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
} }
} }
@ -564,8 +586,8 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
// Encode the 24-bit texture as 16-bit. // Encode the 24-bit texture as 16-bit.
const u32 uniforms[4] = {copy_rect.left, VRAM_HEIGHT - copy_rect.top - copy_rect.GetHeight(), copy_rect.GetWidth(), const u32 uniforms[4] = {copy_rect.left, VRAM_HEIGHT - copy_rect.top - copy_rect.GetHeight(), copy_rect.GetWidth(),
copy_rect.GetHeight()}; copy_rect.GetHeight()};
m_vram_encoding_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->Bind(); m_vram_texture.Bind();
m_vram_read_program.Bind(); m_vram_read_program.Bind();
UploadUniformBlock(uniforms, sizeof(uniforms)); UploadUniformBlock(uniforms, sizeof(uniforms));
glDisable(GL_BLEND); glDisable(GL_BLEND);
@ -574,7 +596,7 @@ void GPU_HW_OpenGL::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
// Readback encoded texture. // Readback encoded texture.
m_vram_encoding_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glPixelStorei(GL_PACK_ALIGNMENT, 2); glPixelStorei(GL_PACK_ALIGNMENT, 2);
glPixelStorei(GL_PACK_ROW_LENGTH, VRAM_WIDTH / 2); glPixelStorei(GL_PACK_ROW_LENGTH, VRAM_WIDTH / 2);
glReadPixels(0, 0, encoded_width, encoded_height, GL_RGBA, GL_UNSIGNED_BYTE, glReadPixels(0, 0, encoded_width, encoded_height, GL_RGBA, GL_UNSIGNED_BYTE,
@ -594,7 +616,7 @@ void GPU_HW_OpenGL::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
width *= m_resolution_scale; width *= m_resolution_scale;
height *= m_resolution_scale; height *= m_resolution_scale;
glScissor(x, m_vram_texture->GetHeight() - y - height, width, height); glScissor(x, m_vram_texture.GetHeight() - y - height, width, height);
// drop precision unless true colour is enabled // drop precision unless true colour is enabled
if (!m_true_color) if (!m_true_color)
@ -635,7 +657,7 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
const u32 scaled_height = height * m_resolution_scale; const u32 scaled_height = height * m_resolution_scale;
const u32 scaled_x = x * m_resolution_scale; const u32 scaled_x = x * m_resolution_scale;
const u32 scaled_y = y * m_resolution_scale; const u32 scaled_y = y * m_resolution_scale;
const u32 scaled_flipped_y = m_vram_texture->GetHeight() - scaled_y - scaled_height; const u32 scaled_flipped_y = m_vram_texture.GetHeight() - scaled_y - scaled_height;
glViewport(scaled_x, scaled_flipped_y, scaled_width, scaled_height); glViewport(scaled_x, scaled_flipped_y, scaled_width, scaled_height);
glDisable(GL_BLEND); glDisable(GL_BLEND);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
@ -679,9 +701,9 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
// have to write to the 1x texture first // have to write to the 1x texture first
if (m_resolution_scale > 1) if (m_resolution_scale > 1)
m_vram_encoding_texture->Bind(); m_vram_encoding_texture.Bind();
else else
m_vram_texture->Bind(); m_vram_texture.Bind();
// lower-left origin flip happens here // lower-left origin flip happens here
const u32 flipped_y = VRAM_HEIGHT - y - height; const u32 flipped_y = VRAM_HEIGHT - y - height;
@ -698,9 +720,9 @@ void GPU_HW_OpenGL::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const void*
const u32 scaled_height = height * m_resolution_scale; const u32 scaled_height = height * m_resolution_scale;
const u32 scaled_x = x * m_resolution_scale; const u32 scaled_x = x * m_resolution_scale;
const u32 scaled_y = y * m_resolution_scale; const u32 scaled_y = y * m_resolution_scale;
const u32 scaled_flipped_y = m_vram_texture->GetHeight() - scaled_y - scaled_height; const u32 scaled_flipped_y = m_vram_texture.GetHeight() - scaled_y - scaled_height;
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
m_vram_encoding_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y,
scaled_x + scaled_width, scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); scaled_x + scaled_width, scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
@ -720,23 +742,23 @@ void GPU_HW_OpenGL::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 wid
height *= m_resolution_scale; height *= m_resolution_scale;
// lower-left origin flip // lower-left origin flip
src_y = m_vram_texture->GetHeight() - src_y - height; src_y = m_vram_texture.GetHeight() - src_y - height;
dst_y = m_vram_texture->GetHeight() - dst_y - height; dst_y = m_vram_texture.GetHeight() - dst_y - height;
if (GLAD_GL_VERSION_4_3) if (GLAD_GL_VERSION_4_3)
{ {
glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture->GetGLId(), glCopyImageSubData(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture.GetGLId(),
GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1); GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1);
} }
else if (GLAD_GL_EXT_copy_image) else if (GLAD_GL_EXT_copy_image)
{ {
glCopyImageSubDataEXT(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture->GetGLId(), glCopyImageSubDataEXT(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture.GetGLId(),
GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1); GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1);
} }
else else
{ {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height, glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
@ -749,26 +771,26 @@ void GPU_HW_OpenGL::UpdateVRAMReadTexture()
const u32 width = scaled_rect.GetWidth(); const u32 width = scaled_rect.GetWidth();
const u32 height = scaled_rect.GetHeight(); const u32 height = scaled_rect.GetHeight();
const u32 x = scaled_rect.left; const u32 x = scaled_rect.left;
const u32 y = m_vram_texture->GetHeight() - scaled_rect.top - height; const u32 y = m_vram_texture.GetHeight() - scaled_rect.top - height;
if (GLAD_GL_VERSION_4_3) if (GLAD_GL_VERSION_4_3)
{ {
glCopyImageSubData(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture->GetGLId(), glCopyImageSubData(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture.GetGLId(),
GL_TEXTURE_2D, 0, x, y, 0, width, height, 1); GL_TEXTURE_2D, 0, x, y, 0, width, height, 1);
} }
else if (GLAD_GL_EXT_copy_image) else if (GLAD_GL_EXT_copy_image)
{ {
glCopyImageSubDataEXT(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture->GetGLId(), glCopyImageSubDataEXT(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture.GetGLId(),
GL_TEXTURE_2D, 0, x, y, 0, width, height, 1); GL_TEXTURE_2D, 0, x, y, 0, width, height, 1);
} }
else else
{ {
m_vram_read_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_read_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glBlitFramebuffer(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
m_vram_texture->BindFramebuffer(GL_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_FRAMEBUFFER);
} }
m_renderer_stats.num_vram_read_texture_updates++; m_renderer_stats.num_vram_read_texture_updates++;

View File

@ -46,13 +46,12 @@ private:
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y); std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(HostDisplay* host_display); void SetCapabilities(HostDisplay* host_display);
void CreateFramebuffer(); bool CreateFramebuffer();
void ClearFramebuffer(); void ClearFramebuffer();
void DestroyFramebuffer();
void CreateVertexBuffer(); bool CreateVertexBuffer();
void CreateUniformBuffer(); bool CreateUniformBuffer();
void CreateTextureBuffer(); bool CreateTextureBuffer();
bool CompilePrograms(); bool CompilePrograms();
void SetDrawState(BatchRenderMode render_mode); void SetDrawState(BatchRenderMode render_mode);
@ -60,10 +59,10 @@ private:
void UploadUniformBlock(const void* data, u32 data_size); void UploadUniformBlock(const void* data, u32 data_size);
// downsample texture - used for readbacks at >1xIR. // downsample texture - used for readbacks at >1xIR.
std::unique_ptr<GL::Texture> m_vram_texture; GL::Texture m_vram_texture;
std::unique_ptr<GL::Texture> m_vram_read_texture; GL::Texture m_vram_read_texture;
std::unique_ptr<GL::Texture> m_vram_encoding_texture; GL::Texture m_vram_encoding_texture;
std::unique_ptr<GL::Texture> m_display_texture; GL::Texture m_display_texture;
std::unique_ptr<GL::StreamBuffer> m_vertex_stream_buffer; std::unique_ptr<GL::StreamBuffer> m_vertex_stream_buffer;
GLuint m_vao_id = 0; GLuint m_vao_id = 0;

View File

@ -33,13 +33,21 @@ bool GPU_HW_OpenGL_ES::Initialize(HostDisplay* host_display, System* system, DMA
if (!GPU_HW::Initialize(host_display, system, dma, interrupt_controller, timers)) if (!GPU_HW::Initialize(host_display, system, dma, interrupt_controller, timers))
return false; return false;
CreateFramebuffer(); if (!CreateFramebuffer())
if (!CompilePrograms()) {
Log_ErrorPrintf("Failed to create framebuffer");
return false; return false;
}
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), 0, 0, if (!CompilePrograms())
m_display_texture->GetWidth(), m_display_texture->GetHeight(), {
m_display_texture->GetWidth(), m_display_texture->GetHeight(), 1.0f); Log_ErrorPrintf("Failed to compile programs");
return false;
}
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), 0, 0,
m_display_texture.GetWidth(), m_display_texture.GetHeight(),
m_display_texture.GetWidth(), m_display_texture.GetHeight(), 1.0f);
RestoreGraphicsAPIState(); RestoreGraphicsAPIState();
return true; return true;
} }
@ -69,8 +77,8 @@ void GPU_HW_OpenGL_ES::ResetGraphicsAPIState()
void GPU_HW_OpenGL_ES::RestoreGraphicsAPIState() void GPU_HW_OpenGL_ES::RestoreGraphicsAPIState()
{ {
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); glViewport(0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
glDisable(GL_CULL_FACE); glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
@ -127,47 +135,50 @@ void GPU_HW_OpenGL_ES::SetCapabilities(HostDisplay* host_display)
m_supports_dual_source_blend = false; m_supports_dual_source_blend = false;
} }
void GPU_HW_OpenGL_ES::CreateFramebuffer() bool GPU_HW_OpenGL_ES::CreateFramebuffer()
{ {
// save old vram texture/fbo, in case we're changing scale // save old vram texture/fbo, in case we're changing scale
auto old_vram_texture = std::move(m_vram_texture); GL::Texture old_vram_texture = std::move(m_vram_texture);
DestroyFramebuffer();
// scale vram size to internal resolution // scale vram size to internal resolution
const u32 texture_width = VRAM_WIDTH * m_resolution_scale; const u32 texture_width = VRAM_WIDTH * m_resolution_scale;
const u32 texture_height = VRAM_HEIGHT * m_resolution_scale; const u32 texture_height = VRAM_HEIGHT * m_resolution_scale;
m_vram_texture = if (!m_vram_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); !m_vram_texture.CreateFramebuffer())
// do we need to restore the framebuffer after a size change?
if (old_vram_texture)
{ {
const bool linear_filter = old_vram_texture->GetWidth() > m_vram_texture->GetWidth(); return false;
Log_DevPrintf("Scaling %ux%u VRAM texture to %ux%u using %s filter", old_vram_texture->GetWidth(),
old_vram_texture->GetHeight(), m_vram_texture->GetWidth(), m_vram_texture->GetHeight(),
linear_filter ? "linear" : "nearest");
glDisable(GL_SCISSOR_TEST);
old_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(0, 0, old_vram_texture->GetWidth(), old_vram_texture->GetHeight(), 0, 0,
m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), GL_COLOR_BUFFER_BIT,
linear_filter ? GL_LINEAR : GL_NEAREST);
glEnable(GL_SCISSOR_TEST);
old_vram_texture.reset();
} }
m_vram_read_texture = // do we need to restore the framebuffer after a size change?
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); if (old_vram_texture.IsValid())
{
const bool linear_filter = old_vram_texture.GetWidth() > m_vram_texture.GetWidth();
Log_DevPrintf("Scaling %ux%u VRAM texture to %ux%u using %s filter", old_vram_texture.GetWidth(),
old_vram_texture.GetHeight(), m_vram_texture.GetWidth(), m_vram_texture.GetHeight(),
linear_filter ? "linear" : "nearest");
glDisable(GL_SCISSOR_TEST);
old_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(0, 0, old_vram_texture.GetWidth(), old_vram_texture.GetHeight(), 0, 0, m_vram_texture.GetWidth(),
m_vram_texture.GetHeight(), GL_COLOR_BUFFER_BIT, linear_filter ? GL_LINEAR : GL_NEAREST);
m_vram_encoding_texture = glEnable(GL_SCISSOR_TEST);
std::make_unique<GL::Texture>(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); old_vram_texture.Destroy();
}
m_display_texture = if (!m_vram_read_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
std::make_unique<GL::Texture>(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false, true); !m_vram_read_texture.CreateFramebuffer() ||
!m_vram_encoding_texture.Create(VRAM_WIDTH, VRAM_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
!m_vram_encoding_texture.CreateFramebuffer() ||
!m_display_texture.Create(texture_width, texture_height, GL_RGBA, GL_UNSIGNED_BYTE, nullptr, false) ||
!m_display_texture.CreateFramebuffer())
{
return false;
}
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
SetFullVRAMDirtyRectangle(); SetFullVRAMDirtyRectangle();
return true;
} }
void GPU_HW_OpenGL_ES::ClearFramebuffer() void GPU_HW_OpenGL_ES::ClearFramebuffer()
@ -179,14 +190,6 @@ void GPU_HW_OpenGL_ES::ClearFramebuffer()
SetFullVRAMDirtyRectangle(); SetFullVRAMDirtyRectangle();
} }
void GPU_HW_OpenGL_ES::DestroyFramebuffer()
{
m_vram_read_texture.reset();
m_vram_texture.reset();
m_vram_encoding_texture.reset();
m_display_texture.reset();
}
bool GPU_HW_OpenGL_ES::CompilePrograms() bool GPU_HW_OpenGL_ES::CompilePrograms()
{ {
GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering, GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_texture_filtering,
@ -290,7 +293,7 @@ void GPU_HW_OpenGL_ES::SetDrawState(BatchRenderMode render_mode)
prog.Bind(); prog.Bind();
if (m_batch.texture_mode != TextureMode::Disabled) if (m_batch.texture_mode != TextureMode::Disabled)
m_vram_read_texture->Bind(); m_vram_read_texture.Bind();
if (m_batch.transparency_mode == TransparencyMode::Disabled || render_mode == BatchRenderMode::OnlyOpaque) if (m_batch.transparency_mode == TransparencyMode::Disabled || render_mode == BatchRenderMode::OnlyOpaque)
{ {
@ -332,7 +335,7 @@ void GPU_HW_OpenGL_ES::SetScissorFromDrawingArea()
const int width = right - left; const int width = right - left;
const int height = bottom - top; const int height = bottom - top;
const int x = left; const int x = left;
const int y = m_vram_texture->GetHeight() - bottom; const int y = m_vram_texture.GetHeight() - bottom;
Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height); Log_DebugPrintf("SetScissor: (%d-%d, %d-%d)", x, x + width, y, y + height);
glScissor(x, y, width, height); glScissor(x, y, width, height);
@ -344,10 +347,10 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
if (m_system->GetSettings().debugging.show_vram) if (m_system->GetSettings().debugging.show_vram)
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), 0, m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())), 0,
m_vram_texture->GetHeight(), m_vram_texture->GetWidth(), m_vram_texture.GetHeight(), m_vram_texture.GetWidth(),
-static_cast<s32>(m_vram_texture->GetHeight()), m_vram_texture->GetWidth(), -static_cast<s32>(m_vram_texture.GetHeight()), m_vram_texture.GetWidth(),
m_vram_texture->GetHeight(), 1.0f); m_vram_texture.GetHeight(), 1.0f);
} }
else else
{ {
@ -367,17 +370,17 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
} }
else if (!m_GPUSTAT.display_area_color_depth_24 && !interlaced) else if (!m_GPUSTAT.display_area_color_depth_24 && !interlaced)
{ {
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_vram_texture.GetGLId())),
scaled_vram_offset_x, m_vram_texture->GetHeight() - scaled_vram_offset_y, scaled_vram_offset_x, m_vram_texture.GetHeight() - scaled_vram_offset_y,
scaled_display_width, -static_cast<s32>(scaled_display_height), scaled_display_width, -static_cast<s32>(scaled_display_height),
m_vram_texture->GetWidth(), m_vram_texture->GetHeight(), m_vram_texture.GetWidth(), m_vram_texture.GetHeight(),
m_crtc_state.display_aspect_ratio); m_crtc_state.display_aspect_ratio);
} }
else else
{ {
const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height; const u32 flipped_vram_offset_y = VRAM_HEIGHT - vram_offset_y - display_height;
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 field_offset = BoolToUInt8(interlaced && m_GPUSTAT.interlaced_field); const u32 field_offset = BoolToUInt8(interlaced && m_GPUSTAT.interlaced_field);
glDisable(GL_BLEND); glDisable(GL_BLEND);
@ -392,15 +395,15 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
{ {
const u32 copy_width = std::min<u32>((display_width * 3) / 2, VRAM_WIDTH - vram_offset_x); const u32 copy_width = std::min<u32>((display_width * 3) / 2, VRAM_WIDTH - vram_offset_x);
const u32 scaled_copy_width = copy_width * m_resolution_scale; const u32 scaled_copy_width = copy_width * m_resolution_scale;
m_vram_encoding_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(scaled_vram_offset_x, scaled_flipped_vram_offset_y, scaled_vram_offset_x + scaled_copy_width, glBlitFramebuffer(scaled_vram_offset_x, scaled_flipped_vram_offset_y, scaled_vram_offset_x + scaled_copy_width,
scaled_flipped_vram_offset_y + scaled_display_height, vram_offset_x, flipped_vram_offset_y, scaled_flipped_vram_offset_y + scaled_display_height, vram_offset_x, flipped_vram_offset_y,
vram_offset_x + copy_width, flipped_vram_offset_y + display_height, GL_COLOR_BUFFER_BIT, vram_offset_x + copy_width, flipped_vram_offset_y + display_height, GL_COLOR_BUFFER_BIT,
GL_NEAREST); GL_NEAREST);
m_display_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_encoding_texture->Bind(); m_vram_encoding_texture.Bind();
glViewport(0, field_offset, display_width, display_height); glViewport(0, field_offset, display_width, display_height);
@ -410,15 +413,15 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
0, display_height, display_width, -static_cast<s32>(display_height), 0, display_height, display_width, -static_cast<s32>(display_height),
m_display_texture->GetWidth(), m_display_texture->GetHeight(), m_display_texture.GetWidth(), m_display_texture.GetHeight(),
m_crtc_state.display_aspect_ratio); m_crtc_state.display_aspect_ratio);
} }
else else
{ {
m_display_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_display_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->Bind(); m_vram_texture.Bind();
glViewport(0, field_offset, scaled_display_width, scaled_display_height); glViewport(0, field_offset, scaled_display_width, scaled_display_height);
@ -428,15 +431,15 @@ void GPU_HW_OpenGL_ES::UpdateDisplay()
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture->GetGLId())), m_host_display->SetDisplayTexture(reinterpret_cast<void*>(static_cast<uintptr_t>(m_display_texture.GetGLId())),
0, scaled_display_height, scaled_display_width, 0, scaled_display_height, scaled_display_width,
-static_cast<s32>(scaled_display_height), m_display_texture->GetWidth(), -static_cast<s32>(scaled_display_height), m_display_texture.GetWidth(),
m_display_texture->GetHeight(), m_crtc_state.display_aspect_ratio); m_display_texture.GetHeight(), m_crtc_state.display_aspect_ratio);
} }
// restore state // restore state
m_vram_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
glViewport(0, 0, m_vram_texture->GetWidth(), m_vram_texture->GetHeight()); glViewport(0, 0, m_vram_texture.GetWidth(), m_vram_texture.GetHeight());
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
} }
} }
@ -450,8 +453,8 @@ void GPU_HW_OpenGL_ES::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
const u32 encoded_height = copy_rect.GetHeight(); const u32 encoded_height = copy_rect.GetHeight();
// Encode the 24-bit texture as 16-bit. // Encode the 24-bit texture as 16-bit.
m_vram_encoding_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->Bind(); m_vram_texture.Bind();
m_vram_read_program.Bind(); m_vram_read_program.Bind();
m_vram_read_program.Uniform2i(0, copy_rect.left, VRAM_HEIGHT - copy_rect.top - copy_rect.GetHeight()); m_vram_read_program.Uniform2i(0, copy_rect.left, VRAM_HEIGHT - copy_rect.top - copy_rect.GetHeight());
m_vram_read_program.Uniform2i(1, copy_rect.GetWidth(), copy_rect.GetHeight()); m_vram_read_program.Uniform2i(1, copy_rect.GetWidth(), copy_rect.GetHeight());
@ -461,7 +464,7 @@ void GPU_HW_OpenGL_ES::ReadVRAM(u32 x, u32 y, u32 width, u32 height)
glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 0, 3);
// Readback encoded texture. // Readback encoded texture.
m_vram_encoding_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glPixelStorei(GL_PACK_ALIGNMENT, 2); glPixelStorei(GL_PACK_ALIGNMENT, 2);
glPixelStorei(GL_PACK_ROW_LENGTH, VRAM_WIDTH / 2); glPixelStorei(GL_PACK_ROW_LENGTH, VRAM_WIDTH / 2);
glReadPixels(0, 0, encoded_width, encoded_height, GL_RGBA, GL_UNSIGNED_BYTE, glReadPixels(0, 0, encoded_width, encoded_height, GL_RGBA, GL_UNSIGNED_BYTE,
@ -481,7 +484,7 @@ void GPU_HW_OpenGL_ES::FillVRAM(u32 x, u32 y, u32 width, u32 height, u32 color)
width *= m_resolution_scale; width *= m_resolution_scale;
height *= m_resolution_scale; height *= m_resolution_scale;
glScissor(x, m_vram_texture->GetHeight() - y - height, width, height); glScissor(x, m_vram_texture.GetHeight() - y - height, width, height);
// drop precision unless true colour is enabled // drop precision unless true colour is enabled
if (!m_true_color) if (!m_true_color)
@ -533,9 +536,9 @@ void GPU_HW_OpenGL_ES::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const voi
// have to write to the 1x texture first // have to write to the 1x texture first
if (m_resolution_scale > 1) if (m_resolution_scale > 1)
m_vram_encoding_texture->Bind(); m_vram_encoding_texture.Bind();
else else
m_vram_texture->Bind(); m_vram_texture.Bind();
// lower-left origin flip happens here // lower-left origin flip happens here
const u32 flipped_y = VRAM_HEIGHT - y - height; const u32 flipped_y = VRAM_HEIGHT - y - height;
@ -550,9 +553,9 @@ void GPU_HW_OpenGL_ES::UpdateVRAM(u32 x, u32 y, u32 width, u32 height, const voi
const u32 scaled_height = height * m_resolution_scale; const u32 scaled_height = height * m_resolution_scale;
const u32 scaled_x = x * m_resolution_scale; const u32 scaled_x = x * m_resolution_scale;
const u32 scaled_y = y * m_resolution_scale; const u32 scaled_y = y * m_resolution_scale;
const u32 scaled_flipped_y = m_vram_texture->GetHeight() - scaled_y - scaled_height; const u32 scaled_flipped_y = m_vram_texture.GetHeight() - scaled_y - scaled_height;
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
m_vram_encoding_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_encoding_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, scaled_x + scaled_width, glBlitFramebuffer(x, flipped_y, x + width, flipped_y + height, scaled_x, scaled_flipped_y, scaled_x + scaled_width,
scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST); scaled_flipped_y + scaled_height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
@ -571,18 +574,18 @@ void GPU_HW_OpenGL_ES::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32
height *= m_resolution_scale; height *= m_resolution_scale;
// lower-left origin flip // lower-left origin flip
src_y = m_vram_texture->GetHeight() - src_y - height; src_y = m_vram_texture.GetHeight() - src_y - height;
dst_y = m_vram_texture->GetHeight() - dst_y - height; dst_y = m_vram_texture.GetHeight() - dst_y - height;
if (GLAD_GL_EXT_copy_image) if (GLAD_GL_EXT_copy_image)
{ {
glCopyImageSubDataEXT(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture->GetGLId(), glCopyImageSubDataEXT(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, src_x, src_y, 0, m_vram_texture.GetGLId(),
GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1); GL_TEXTURE_2D, 0, dst_x, dst_y, 0, width, height, 1);
} }
else else
{ {
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height, glBlitFramebuffer(src_x, src_y, src_x + width, src_y + height, dst_x, dst_y, dst_x + width, dst_y + height,
GL_COLOR_BUFFER_BIT, GL_NEAREST); GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
@ -595,21 +598,21 @@ void GPU_HW_OpenGL_ES::UpdateVRAMReadTexture()
const u32 width = scaled_rect.GetWidth(); const u32 width = scaled_rect.GetWidth();
const u32 height = scaled_rect.GetHeight(); const u32 height = scaled_rect.GetHeight();
const u32 x = scaled_rect.left; const u32 x = scaled_rect.left;
const u32 y = m_vram_texture->GetHeight() - scaled_rect.top - height; const u32 y = m_vram_texture.GetHeight() - scaled_rect.top - height;
if (GLAD_GL_EXT_copy_image) if (GLAD_GL_EXT_copy_image)
{ {
glCopyImageSubDataEXT(m_vram_texture->GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture->GetGLId(), glCopyImageSubDataEXT(m_vram_texture.GetGLId(), GL_TEXTURE_2D, 0, x, y, 0, m_vram_read_texture.GetGLId(),
GL_TEXTURE_2D, 0, x, y, 0, width, height, 1); GL_TEXTURE_2D, 0, x, y, 0, width, height, 1);
} }
else else
{ {
m_vram_read_texture->BindFramebuffer(GL_DRAW_FRAMEBUFFER); m_vram_read_texture.BindFramebuffer(GL_DRAW_FRAMEBUFFER);
m_vram_texture->BindFramebuffer(GL_READ_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_READ_FRAMEBUFFER);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
glBlitFramebuffer(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST); glBlitFramebuffer(x, y, x + width, y + height, x, y, x + width, y + height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
glEnable(GL_SCISSOR_TEST); glEnable(GL_SCISSOR_TEST);
m_vram_texture->BindFramebuffer(GL_FRAMEBUFFER); m_vram_texture.BindFramebuffer(GL_FRAMEBUFFER);
} }
m_renderer_stats.num_vram_read_texture_updates++; m_renderer_stats.num_vram_read_texture_updates++;

View File

@ -5,7 +5,6 @@
#include "glad.h" #include "glad.h"
#include "gpu_hw.h" #include "gpu_hw.h"
#include <array> #include <array>
#include <memory>
#include <tuple> #include <tuple>
class GPU_HW_OpenGL_ES : public GPU_HW class GPU_HW_OpenGL_ES : public GPU_HW
@ -46,9 +45,8 @@ private:
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y); std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(HostDisplay* host_display); void SetCapabilities(HostDisplay* host_display);
void CreateFramebuffer(); bool CreateFramebuffer();
void ClearFramebuffer(); void ClearFramebuffer();
void DestroyFramebuffer();
bool CompilePrograms(); bool CompilePrograms();
void SetVertexPointers(); void SetVertexPointers();
@ -56,10 +54,10 @@ private:
void SetScissorFromDrawingArea(); void SetScissorFromDrawingArea();
// downsample texture - used for readbacks at >1xIR. // downsample texture - used for readbacks at >1xIR.
std::unique_ptr<GL::Texture> m_vram_texture; GL::Texture m_vram_texture;
std::unique_ptr<GL::Texture> m_vram_read_texture; GL::Texture m_vram_read_texture;
std::unique_ptr<GL::Texture> m_vram_encoding_texture; GL::Texture m_vram_encoding_texture;
std::unique_ptr<GL::Texture> m_display_texture; GL::Texture m_display_texture;
std::vector<BatchVertex> m_vertex_buffer; std::vector<BatchVertex> m_vertex_buffer;

View File

@ -339,8 +339,8 @@ void main()
glGenVertexArrays(1, &m_display_vao); glGenVertexArrays(1, &m_display_vao);
m_app_icon_texture = if (!m_app_icon_texture.Create(APP_ICON_WIDTH, APP_ICON_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, APP_ICON_DATA, true))
std::make_unique<GL::Texture>(APP_ICON_WIDTH, APP_ICON_HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, APP_ICON_DATA, true); return false;
// samplers // samplers
glGenSamplers(1, &m_display_nearest_sampler); glGenSamplers(1, &m_display_nearest_sampler);

View File

@ -52,7 +52,7 @@ private:
int m_window_width = 0; int m_window_width = 0;
int m_window_height = 0; int m_window_height = 0;
std::unique_ptr<GL::Texture> m_app_icon_texture = nullptr; GL::Texture m_app_icon_texture;
GL::Program m_display_program; GL::Program m_display_program;
GLuint m_display_vao = 0; GLuint m_display_vao = 0;