GPU/HW: Support OpenGL ES

This commit is contained in:
Connor McLaughlin 2019-11-06 01:33:09 +10:00
parent b28610e30b
commit ff8cef4da3
5 changed files with 97 additions and 54 deletions

View File

@ -240,7 +240,7 @@ bool GPU_HW_D3D11::CreateBatchInputLayout()
{"ATTR", 3, DXGI_FORMAT_R32_SINT, 0, offsetof(BatchVertex, texpage), D3D11_INPUT_PER_VERTEX_DATA, 0}}}; {"ATTR", 3, DXGI_FORMAT_R32_SINT, 0, offsetof(BatchVertex, texpage), D3D11_INPUT_PER_VERTEX_DATA, 0}}};
// we need a vertex shader... // we need a vertex shader...
GPU_HW_ShaderGen shadergen(GPU_HW_ShaderGen::API::D3D11, m_resolution_scale, m_true_color); GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color);
ComPtr<ID3DBlob> vs_bytecode = D3D11::ShaderCompiler::CompileShader( ComPtr<ID3DBlob> vs_bytecode = D3D11::ShaderCompiler::CompileShader(
D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), shadergen.GenerateBatchVertexShader(true), false); D3D11::ShaderCompiler::Type::Vertex, m_device->GetFeatureLevel(), shadergen.GenerateBatchVertexShader(true), false);
if (!vs_bytecode) if (!vs_bytecode)
@ -318,7 +318,7 @@ bool GPU_HW_D3D11::CreateStateObjects()
bool GPU_HW_D3D11::CompileShaders() bool GPU_HW_D3D11::CompileShaders()
{ {
const bool debug = false; const bool debug = false;
GPU_HW_ShaderGen shadergen(GPU_HW_ShaderGen::API::D3D11, m_resolution_scale, m_true_color); GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color);
m_screen_quad_vertex_shader = D3D11::ShaderCompiler::CompileAndCreateVertexShader( m_screen_quad_vertex_shader = D3D11::ShaderCompiler::CompileAndCreateVertexShader(
m_device.Get(), shadergen.GenerateScreenQuadVertexShader(), debug); m_device.Get(), shadergen.GenerateScreenQuadVertexShader(), debug);

View File

@ -11,6 +11,7 @@ GPU_HW_OpenGL::GPU_HW_OpenGL() : GPU_HW() {}
GPU_HW_OpenGL::~GPU_HW_OpenGL() GPU_HW_OpenGL::~GPU_HW_OpenGL()
{ {
// TODO: Destroy objects...
if (m_host_display) if (m_host_display)
{ {
m_host_display->SetDisplayTexture(nullptr, 0, 0, 0, 0, 0, 0, 1.0f); m_host_display->SetDisplayTexture(nullptr, 0, 0, 0, 0, 0, 0, 1.0f);
@ -21,13 +22,14 @@ GPU_HW_OpenGL::~GPU_HW_OpenGL()
bool GPU_HW_OpenGL::Initialize(HostDisplay* host_display, System* system, DMA* dma, bool GPU_HW_OpenGL::Initialize(HostDisplay* host_display, System* system, DMA* dma,
InterruptController* interrupt_controller, Timers* timers) InterruptController* interrupt_controller, Timers* timers)
{ {
if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGL) if (host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGL &&
host_display->GetRenderAPI() != HostDisplay::RenderAPI::OpenGLES)
{ {
Log_ErrorPrintf("Host render API type is incompatible"); Log_ErrorPrintf("Host render API type is incompatible");
return false; return false;
} }
SetCapabilities(); SetCapabilities(host_display);
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;
@ -108,8 +110,10 @@ 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)); return std::make_tuple(x, static_cast<s32>(static_cast<s32>(VRAM_HEIGHT) - y));
} }
void GPU_HW_OpenGL::SetCapabilities() void GPU_HW_OpenGL::SetCapabilities(HostDisplay* host_display)
{ {
m_is_gles = (host_display->GetRenderAPI() == HostDisplay::RenderAPI::OpenGLES);
GLint max_texture_size = VRAM_WIDTH; GLint max_texture_size = VRAM_WIDTH;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
Log_InfoPrintf("Max texture size: %dx%d", max_texture_size, max_texture_size); Log_InfoPrintf("Max texture size: %dx%d", max_texture_size, max_texture_size);
@ -128,9 +132,17 @@ void GPU_HW_OpenGL::SetCapabilities()
if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_EXT_copy_image) if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_EXT_copy_image)
Log_WarningPrintf("GL_EXT_copy_image missing, this may affect performance."); Log_WarningPrintf("GL_EXT_copy_image missing, this may affect performance.");
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, reinterpret_cast<GLint*>(&m_max_texture_buffer_size)); m_supports_texture_buffer = (GLAD_GL_VERSION_3_1 || GLAD_GL_ES_VERSION_3_2);
if (m_max_texture_buffer_size < VRAM_WIDTH * VRAM_HEIGHT) if (m_uniform_stream_buffer)
Log_WarningPrintf("Maximum texture buffer size is less than VRAM size, VRAM writes may be slower."); {
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, reinterpret_cast<GLint*>(&m_max_texture_buffer_size));
if (m_max_texture_buffer_size < VRAM_WIDTH * VRAM_HEIGHT)
Log_WarningPrintf("Maximum texture buffer size is less than VRAM size, VRAM writes may be slower.");
}
else
{
Log_WarningPrintf("Texture buffers are not supported, VRAM writes will be slower.");
}
} }
void GPU_HW_OpenGL::CreateFramebuffer() void GPU_HW_OpenGL::CreateFramebuffer()
@ -234,16 +246,19 @@ void GPU_HW_OpenGL::CreateTextureBuffer()
if (!m_texture_stream_buffer) if (!m_texture_stream_buffer)
Panic("Failed to create texture stream buffer"); Panic("Failed to create texture stream buffer");
glGenTextures(1, &m_texture_buffer_r16ui_texture); if (m_max_texture_buffer_size > 0)
glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer_r16ui_texture); {
glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, m_texture_stream_buffer->GetGLBufferId()); glGenTextures(1, &m_texture_buffer_r16ui_texture);
glBindTexture(GL_TEXTURE_BUFFER, m_texture_buffer_r16ui_texture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_R16UI, m_texture_stream_buffer->GetGLBufferId());
}
m_texture_stream_buffer->Unbind(); m_texture_stream_buffer->Unbind();
} }
bool GPU_HW_OpenGL::CompilePrograms() bool GPU_HW_OpenGL::CompilePrograms()
{ {
GPU_HW_ShaderGen shadergen(GPU_HW_ShaderGen::API::OpenGL, m_resolution_scale, m_true_color); GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color);
for (u32 render_mode = 0; render_mode < 4; render_mode++) for (u32 render_mode = 0; render_mode < 4; render_mode++)
{ {
@ -269,7 +284,8 @@ bool GPU_HW_OpenGL::CompilePrograms()
prog.BindAttribute(3, "a_texpage"); prog.BindAttribute(3, "a_texpage");
} }
prog.BindFragData(0, "o_col0"); if (!m_is_gles)
prog.BindFragData(0, "o_col0");
if (!prog.Link()) if (!prog.Link())
return false; return false;
@ -295,7 +311,9 @@ bool GPU_HW_OpenGL::CompilePrograms()
if (!prog.Compile(vs, fs)) if (!prog.Compile(vs, fs))
return false; return false;
prog.BindFragData(0, "o_col0"); if (!m_is_gles)
prog.BindFragData(0, "o_col0");
if (!prog.Link()) if (!prog.Link())
return false; return false;
@ -306,21 +324,26 @@ bool GPU_HW_OpenGL::CompilePrograms()
} }
} }
if (!m_vram_write_program.Compile(shadergen.GenerateScreenQuadVertexShader(), if (m_supports_texture_buffer)
shadergen.GenerateVRAMWriteFragmentShader()))
{ {
return false; if (!m_vram_write_program.Compile(shadergen.GenerateScreenQuadVertexShader(),
shadergen.GenerateVRAMWriteFragmentShader()))
{
return false;
}
if (!m_is_gles)
m_vram_write_program.BindFragData(0, "o_col0");
if (!m_vram_write_program.Link())
return false;
m_vram_write_program.BindUniformBlock("UBOBlock", 1);
m_vram_write_program.Bind();
m_vram_write_program.Uniform1i("samp0", 0);
} }
m_vram_write_program.BindFragData(0, "o_col0");
if (!m_vram_write_program.Link())
return false;
m_vram_write_program.BindUniformBlock("UBOBlock", 1);
m_vram_write_program.Bind();
m_vram_write_program.Uniform1i("samp0", 0);
return true; return true;
} }

View File

@ -45,7 +45,7 @@ private:
std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y); std::tuple<s32, s32> ConvertToFramebufferCoordinates(s32 x, s32 y);
void SetCapabilities(); void SetCapabilities(HostDisplay* host_display);
void CreateFramebuffer(); void CreateFramebuffer();
void ClearFramebuffer(); void ClearFramebuffer();
void DestroyFramebuffer(); void DestroyFramebuffer();
@ -74,10 +74,13 @@ private:
std::unique_ptr<GL::StreamBuffer> m_texture_stream_buffer; std::unique_ptr<GL::StreamBuffer> m_texture_stream_buffer;
GLuint m_texture_buffer_r16ui_texture = 0; GLuint m_texture_buffer_r16ui_texture = 0;
u32 m_uniform_buffer_alignment = 1;
u32 m_max_texture_buffer_size = 0;
std::array<std::array<std::array<GL::Program, 2>, 9>, 4> m_render_programs; // [render_mode][texture_mode][dithering] std::array<std::array<std::array<GL::Program, 2>, 9>, 4> m_render_programs; // [render_mode][texture_mode][dithering]
std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced] std::array<std::array<GL::Program, 2>, 2> m_display_programs; // [depth_24][interlaced]
GL::Program m_vram_write_program; GL::Program m_vram_write_program;
u32 m_uniform_buffer_alignment = 1;
u32 m_max_texture_buffer_size = 0;
bool m_is_gles = false;
bool m_supports_texture_buffer = false;
}; };

View File

@ -1,7 +1,9 @@
#include "gpu_hw_shadergen.h" #include "gpu_hw_shadergen.h"
#include <glad.h>
GPU_HW_ShaderGen::GPU_HW_ShaderGen(API backend, u32 resolution_scale, bool true_color) GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color)
: m_backend(backend), m_resolution_scale(resolution_scale), m_true_color(true_color), m_glsl(backend != API::D3D11) : m_render_api(render_api), m_resolution_scale(resolution_scale), m_true_color(true_color),
m_glsl(render_api != HostDisplay::RenderAPI::D3D11)
{ {
} }
@ -9,20 +11,37 @@ GPU_HW_ShaderGen::~GPU_HW_ShaderGen() = default;
static void DefineMacro(std::stringstream& ss, const char* name, bool enabled) static void DefineMacro(std::stringstream& ss, const char* name, bool enabled)
{ {
if (enabled) ss << "#define " << name << " " << BoolToUInt32(enabled) << "\n";
ss << "#define " << name << " 1\n";
else
ss << "/* #define " << name << " 0 */\n";
} }
void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss) void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss)
{ {
if (m_backend == API::OpenGL) if (m_render_api == HostDisplay::RenderAPI::OpenGL)
{ {
ss << "#version 330 core\n\n"; ss << "#version 330 core\n\n";
ss << "#define API_OPENGL 1\n"; ss << "#define API_OPENGL 1\n";
} }
else if (m_backend == API::D3D11) else if (m_render_api == HostDisplay::RenderAPI::OpenGLES)
{
if (GLAD_GL_ES_VERSION_3_2)
ss << "#version 320 es\n\n";
else if (GLAD_GL_ES_VERSION_3_1)
ss << "#version 310 es\n\n";
else
ss << "#version 300 es\n\n";
ss << "precision highp float;\n";
ss << "precision highp int;\n";
ss << "precision highp sampler2D;\n";
if (GLAD_GL_ES_VERSION_3_2)
ss << "precision highp usamplerBuffer;\n";
ss << "\n";
ss << "#define API_OPENGL 1\n";
ss << "#define API_OPENGL_ES 1\n";
}
else if (m_render_api == HostDisplay::RenderAPI::D3D11)
{ {
ss << "#define API_D3D11 1\n"; ss << "#define API_D3D11 1\n";
} }
@ -67,7 +86,7 @@ void GPU_HW_ShaderGen::WriteCommonFunctions(std::stringstream& ss)
float fixYCoord(float y) float fixYCoord(float y)
{ {
#if API_OPENGL #if API_OPENGL || API_OPENGL_ES
return 1.0 - RCP_VRAM_SIZE.y - y; return 1.0 - RCP_VRAM_SIZE.y - y;
#else #else
return y; return y;
@ -76,7 +95,7 @@ float fixYCoord(float y)
int fixYCoord(int y) int fixYCoord(int y)
{ {
#if API_OPENGL #if API_OPENGL || API_OPENGL_ES
return VRAM_SIZE.y - y - 1; return VRAM_SIZE.y - y - 1;
#else #else
return y; return y;
@ -447,7 +466,12 @@ int4 SampleFromVRAM(int4 texpage, float2 coord)
#if TEXTURED #if TEXTURED
int4 texcol = SampleFromVRAM(v_texpage, v_tex0); int4 texcol = SampleFromVRAM(v_texpage, v_tex0);
if (all(texcol == int4(0.0, 0.0, 0.0, 0.0))) #if GLSL
bool transparent = (texcol == int4(0.0, 0.0, 0.0, 0.0));
#else
bool transparent = (all(texcol == int4(0.0, 0.0, 0.0, 0.0)));
#endif
if (transparent)
discard; discard;
// Grab semitransparent bit from the texture color. // Grab semitransparent bit from the texture color.
@ -565,7 +589,7 @@ std::string GPU_HW_ShaderGen::GenerateScreenQuadVertexShader()
{ {
v_tex0 = float2(float((v_id << 1) & 2u), float(v_id & 2u)); v_tex0 = float2(float((v_id << 1) & 2u), float(v_id & 2u));
v_pos = float4(v_tex0 * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f); v_pos = float4(v_tex0 * float2(2.0f, -2.0f) + float2(-1.0f, 1.0f), 0.0f, 1.0f);
#if API_OPENGL #if API_OPENGL || API_OPENGL_ES
v_pos.y = -gl_Position.y; v_pos.y = -gl_Position.y;
#endif #endif
} }
@ -695,7 +719,7 @@ std::string GPU_HW_ShaderGen::GenerateVRAMWriteFragmentShader()
int2 coords = int2(v_pos.xy) / int2(RESOLUTION_SCALE, RESOLUTION_SCALE); int2 coords = int2(v_pos.xy) / int2(RESOLUTION_SCALE, RESOLUTION_SCALE);
int2 offset = coords - u_base_coords; int2 offset = coords - u_base_coords;
#if API_OPENGL #if API_OPENGL || API_OPENGL_ES
// Lower-left origin flip for OpenGL // Lower-left origin flip for OpenGL
offset.y = u_size.y - offset.y - 1; offset.y = u_size.y - offset.y - 1;
#endif #endif

View File

@ -1,23 +1,15 @@
#pragma once #pragma once
#include "gpu_hw.h" #include "gpu_hw.h"
#include "host_display.h"
#include <sstream> #include <sstream>
#include <string> #include <string>
class GPU_HW_ShaderGen class GPU_HW_ShaderGen
{ {
public: public:
enum class API GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolution_scale, bool true_color);
{
OpenGL,
D3D11
};
public:
GPU_HW_ShaderGen(API backend, u32 resolution_scale, bool true_color);
~GPU_HW_ShaderGen(); ~GPU_HW_ShaderGen();
void Init(API backend, u32 resolution_scale, bool true_color);
std::string GenerateBatchVertexShader(bool textured); std::string GenerateBatchVertexShader(bool textured);
std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode, std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode,
bool dithering); bool dithering);
@ -28,10 +20,11 @@ public:
std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced); std::string GenerateDisplayFragmentShader(bool depth_24bit, bool interlaced);
std::string GenerateVRAMWriteFragmentShader(); std::string GenerateVRAMWriteFragmentShader();
API m_backend; HostDisplay::RenderAPI m_render_api;
u32 m_resolution_scale; u32 m_resolution_scale;
bool m_true_color; bool m_true_color;
bool m_glsl; bool m_glsl;
bool m_glsl_es;
private: private:
void WriteHeader(std::stringstream& ss); void WriteHeader(std::stringstream& ss);