gl: Autodetect supported OpenGL extensions

cleanup
This commit is contained in:
kd-11 2017-04-04 19:14:36 +03:00
commit ac3b22902a
7 changed files with 145 additions and 61 deletions

View file

@ -518,19 +518,37 @@ void GLGSRender::on_init_thread()
GSRender::on_init_thread(); GSRender::on_init_thread();
gl::init(); gl::init();
if (g_cfg_rsx_debug_output) if (g_cfg_rsx_debug_output)
gl::enable_debugging(); gl::enable_debugging();
LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VERSION)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VERSION));
LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VENDOR)); LOG_NOTICE(RSX, "%s", (const char*)glGetString(GL_VENDOR));
auto gl_caps = gl::get_driver_caps();
if (!gl_caps.ARB_texture_buffer_supported)
{
fmt::throw_exception("Failed to initialize OpenGL renderer. ARB_texture_buffer_object is required but not supported by your GPU");
}
if (!gl_caps.ARB_dsa_supported && !gl_caps.EXT_dsa_supported)
{
fmt::throw_exception("Failed to initialize OpenGL renderer. ARB_direct_state_access or EXT_direct_state_access is required but not supported by your GPU");
}
//Use industry standard resource alignment values as defaults
m_uniform_buffer_offset_align = 256;
m_min_texbuffer_alignment = 256;
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_uniform_buffer_offset_align); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &m_uniform_buffer_offset_align);
glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &m_min_texbuffer_alignment); glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, &m_min_texbuffer_alignment);
m_vao.create(); m_vao.create();
const u32 texture_index_offset = const u32 texture_index_offset = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count;
rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count;
for (int index = 0; index < rsx::limits::vertex_count; ++index) for (int index = 0; index < rsx::limits::vertex_count; ++index)
{ {
auto &tex = m_gl_attrib_buffers[index]; auto &tex = m_gl_attrib_buffers[index];
@ -541,6 +559,12 @@ void GLGSRender::on_init_thread()
tex.bind(); tex.bind();
} }
if (!gl_caps.ARB_buffer_storage_supported)
{
LOG_WARNING(RSX, "Forcing use of legacy OpenGL buffers because ARB_buffer_storage is not supported");
g_cfg_rsx_gl_legacy_buffers = true;
}
if (g_cfg_rsx_gl_legacy_buffers) if (g_cfg_rsx_gl_legacy_buffers)
{ {
LOG_WARNING(RSX, "Using legacy openGL buffers."); LOG_WARNING(RSX, "Using legacy openGL buffers.");
@ -570,7 +594,13 @@ void GLGSRender::on_init_thread()
m_vao.element_array_buffer = *m_index_ring_buffer; m_vao.element_array_buffer = *m_index_ring_buffer;
if (g_cfg_rsx_overlay) if (g_cfg_rsx_overlay)
m_text_printer.init(); {
if (gl_caps.ARB_shader_draw_parameters_supported)
{
m_text_printer.init();
m_text_printer.set_enabled(true);
}
}
for (int i = 0; i < rsx::limits::fragment_textures_count; ++i) for (int i = 0; i < rsx::limits::fragment_textures_count; ++i)
{ {
@ -783,7 +813,7 @@ bool GLGSRender::load_program()
fragment_constants_offset = mapping.second; fragment_constants_offset = mapping.second;
if (fragment_constants_size) if (fragment_constants_size)
m_prog_buffer.fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), gsl::narrow<int>(fragment_constants_size) }, fragment_program); m_prog_buffer.fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), gsl::narrow<int>(fragment_constants_size) }, fragment_program);
// Fragment state // Fragment state
fill_fragment_state_buffer(buf+fragment_constants_size, fragment_program); fill_fragment_state_buffer(buf+fragment_constants_size, fragment_program);
@ -796,7 +826,7 @@ bool GLGSRender::load_program()
{ {
m_scale_offset_buffer->unmap(); m_scale_offset_buffer->unmap();
m_fragment_constants_buffer->unmap(); m_fragment_constants_buffer->unmap();
if (m_transform_constants_dirty) m_transform_constants_buffer->unmap(); if (m_transform_constants_dirty) m_transform_constants_buffer->unmap();
} }
@ -896,7 +926,7 @@ void GLGSRender::flip(int buffer)
{ {
gl::screen.bind(); gl::screen.bind();
glViewport(0, 0, m_frame->client_width(), m_frame->client_height()); glViewport(0, 0, m_frame->client_width(), m_frame->client_height());
m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls)); m_text_printer.print_text(0, 0, m_frame->client_width(), m_frame->client_height(), "draw calls: " + std::to_string(m_draw_calls));
m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us"); m_text_printer.print_text(0, 18, m_frame->client_width(), m_frame->client_height(), "draw call setup: " + std::to_string(m_begin_time) + "us");
m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us"); m_text_printer.print_text(0, 36, m_frame->client_width(), m_frame->client_height(), "vertex upload time: " + std::to_string(m_vertex_upload_time) + "us");

View file

@ -17,7 +17,7 @@ struct work_item
{ {
std::condition_variable cv; std::condition_variable cv;
std::mutex guard_mutex; std::mutex guard_mutex;
u32 address_to_flush = 0; u32 address_to_flush = 0;
gl::texture_cache::cached_texture_section *section_to_flush = nullptr; gl::texture_cache::cached_texture_section *section_to_flush = nullptr;
@ -30,7 +30,7 @@ struct gcm_buffer_info
{ {
u32 address = 0; u32 address = 0;
u32 pitch = 0; u32 pitch = 0;
bool is_depth_surface; bool is_depth_surface;
rsx::surface_color_format color_format; rsx::surface_color_format color_format;
@ -67,7 +67,7 @@ private:
gl::texture_cache m_gl_texture_cache; gl::texture_cache m_gl_texture_cache;
gl::texture m_gl_attrib_buffers[rsx::limits::vertex_count]; gl::texture m_gl_attrib_buffers[rsx::limits::vertex_count];
std::unique_ptr<gl::ring_buffer> m_attrib_ring_buffer; std::unique_ptr<gl::ring_buffer> m_attrib_ring_buffer;
std::unique_ptr<gl::ring_buffer> m_fragment_constants_buffer; std::unique_ptr<gl::ring_buffer> m_fragment_constants_buffer;
std::unique_ptr<gl::ring_buffer> m_transform_constants_buffer; std::unique_ptr<gl::ring_buffer> m_transform_constants_buffer;
@ -82,7 +82,7 @@ private:
//Compare to see if transform matrix have changed //Compare to see if transform matrix have changed
size_t m_transform_buffer_hash = 0; size_t m_transform_buffer_hash = 0;
GLint m_min_texbuffer_alignment = 256; GLint m_min_texbuffer_alignment = 256;
GLint m_uniform_buffer_offset_align = 256; GLint m_uniform_buffer_offset_align = 256;

View file

@ -4,6 +4,7 @@
namespace gl namespace gl
{ {
capabilities g_driver_caps;
const fbo screen{}; const fbo screen{};
GLenum draw_mode(rsx::primitive_type in) GLenum draw_mode(rsx::primitive_type in)
@ -49,6 +50,14 @@ namespace gl
#endif #endif
} }
capabilities &get_driver_caps()
{
if (!g_driver_caps.initialized)
g_driver_caps.initialize();
return g_driver_caps;
}
void fbo::create() void fbo::create()
{ {
glGenFramebuffers(1, &m_id); glGenFramebuffers(1, &m_id);

View file

@ -53,7 +53,10 @@ namespace gl
#define __glcheck #define __glcheck
#endif #endif
class capabilities;
void enable_debugging(); void enable_debugging();
capabilities& get_driver_caps();
class exception : public std::exception class exception : public std::exception
{ {
@ -67,6 +70,69 @@ namespace gl
} }
}; };
class capabilities
{
public:
bool EXT_dsa_supported = false;
bool ARB_dsa_supported = false;
bool ARB_buffer_storage_supported = false;
bool ARB_texture_buffer_supported = false;
bool ARB_shader_draw_parameters_supported = false;
bool initialized = false;
void initialize()
{
int find_count = 5;
int ext_count = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_count);
for (int i = 0; i < ext_count; i++)
{
if (!find_count) break;
const char *ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
const auto ext_name = std::string(ext);
if (ext_name == "GL_ARB_shader_draw_parameters")
{
ARB_shader_draw_parameters_supported = true;
find_count --;
continue;
}
if (ext_name == "GL_EXT_direct_state_access")
{
EXT_dsa_supported = true;
find_count --;
continue;
}
if (ext_name == "GL_ARB_direct_state_access")
{
ARB_dsa_supported = true;
find_count --;
continue;
}
if (ext_name == "GL_ARB_buffer_storage")
{
ARB_buffer_storage_supported = true;
find_count --;
continue;
}
if (ext_name == "GL_ARB_texture_buffer_object")
{
ARB_texture_buffer_supported = true;
find_count --;
continue;
}
}
initialized = true;
}
};
class fence class fence
{ {
GLsync m_value = nullptr; GLsync m_value = nullptr;
@ -218,7 +284,7 @@ namespace gl
depth_stencil = depth | stencil depth_stencil = depth | stencil
}; };
class pixel_pack_settings class pixel_pack_settings
{ {
bool m_swap_bytes = false; bool m_swap_bytes = false;
@ -705,7 +771,7 @@ namespace gl
m_fence.wait_for_signal(); m_fence.wait_for_signal();
remove(); remove();
} }
buffer::create(); buffer::create();
glBindBuffer((GLenum)m_target, m_id); glBindBuffer((GLenum)m_target, m_id);
@ -732,7 +798,7 @@ namespace gl
{ {
if (!m_fence.is_empty()) if (!m_fence.is_empty())
m_fence.wait_for_signal(); m_fence.wait_for_signal();
m_data_loc = 0; m_data_loc = 0;
offset = 0; offset = 0;
} }
@ -792,7 +858,7 @@ namespace gl
buffer::create(); buffer::create();
buffer::data(size, data); buffer::data(size, data);
m_memory_mapping = nullptr; m_memory_mapping = nullptr;
m_data_loc = 0; m_data_loc = 0;
m_limit = size; m_limit = size;
@ -839,7 +905,7 @@ namespace gl
//Overallocate slightly for the next allocation if requested size is too small //Overallocate slightly for the next allocation if requested size is too small
unmap(); unmap();
reserve_storage_on_heap(std::max(real_size, 4096U)); reserve_storage_on_heap(std::max(real_size, 4096U));
offset = m_data_loc; offset = m_data_loc;
if (m_data_loc) offset = align(offset, alignment); if (m_data_loc) offset = align(offset, alignment);
@ -849,7 +915,7 @@ namespace gl
m_data_loc = offset + alloc_size; m_data_loc = offset + alloc_size;
m_mapped_bytes -= real_size; m_mapped_bytes -= real_size;
u32 local_offset = (offset - m_mapping_offset); u32 local_offset = (offset - m_mapping_offset);
return std::make_pair(((char*)m_memory_mapping) + local_offset, offset); return std::make_pair(((char*)m_memory_mapping) + local_offset, offset);
} }
@ -1186,7 +1252,7 @@ namespace gl
} }
glGetIntegerv(pname, &m_last_binding); glGetIntegerv(pname, &m_last_binding);
new_binding.bind(); new_binding.bind();
m_target = (GLenum)new_binding.get_target(); m_target = (GLenum)new_binding.get_target();
} }
@ -1453,22 +1519,12 @@ namespace gl
if (get_target() != target::textureBuffer) if (get_target() != target::textureBuffer)
fmt::throw_exception("OpenGL error: texture cannot copy from buffer" HERE); fmt::throw_exception("OpenGL error: texture cannot copy from buffer" HERE);
/* if (!offset) auto caps = get_driver_caps();
{
copy_from(buf, gl_format_type);
return;
}*/
if (glTextureBufferRangeEXT == nullptr) if (caps.EXT_dsa_supported)
fmt::throw_exception("OpenGL error: partial buffer access for textures is unsupported on your system" HERE); __glcheck glTextureBufferRangeEXT(id(), (GLenum)target::textureBuffer, gl_format_type, buf.id(), offset, length);
else
__glcheck glTextureBufferRangeEXT(id(), (GLenum)target::textureBuffer, gl_format_type, buf.id(), offset, length); __glcheck glTextureBufferRange(id(), gl_format_type, buf.id(), offset, length);
}
void copy_from(buffer &buf, u32 gl_format_type)
{
save_binding_state save(*this);
__glcheck glTexBuffer((GLenum)target::textureBuffer, gl_format_type, buf.id());
} }
void copy_from(const buffer& buf, texture::format format, texture::type type, class pixel_unpack_settings pixel_settings) void copy_from(const buffer& buf, texture::format format, texture::type type, class pixel_unpack_settings pixel_settings)
@ -1863,7 +1919,7 @@ namespace gl
void recreate(); void recreate();
void draw_buffer(const attachment& buffer) const; void draw_buffer(const attachment& buffer) const;
void draw_buffers(const std::initializer_list<attachment>& indexes) const; void draw_buffers(const std::initializer_list<attachment>& indexes) const;
void read_buffer(const attachment& buffer) const; void read_buffer(const attachment& buffer) const;
void draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first = 0) const; void draw_arrays(rsx::primitive_type mode, GLsizei count, GLint first = 0) const;

View file

@ -171,6 +171,7 @@ OPENGL_PROC(PFNGLBINDBUFFERBASEPROC, BindBufferBase);
OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays); OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT); OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
OPENGL_PROC(PFNGLGETTEXTUREIMAGEPROC, GetTextureImage);
//Sampler Objects //Sampler Objects
OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers); OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers);
@ -180,8 +181,8 @@ OPENGL_PROC(PFNGLSAMPLERPARAMETERIPROC, SamplerParameteri);
OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv); OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv);
//Texture Buffers //Texture Buffers
OPENGL_PROC(PFNGLTEXBUFFERPROC, TexBuffer);
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT); OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEPROC, TextureBufferRange);
//ARB_Copy_Image //ARB_Copy_Image
OPENGL_PROC(PFNGLCOPYIMAGESUBDATAPROC, CopyImageSubData); OPENGL_PROC(PFNGLCOPYIMAGESUBDATAPROC, CopyImageSubData);

View file

@ -85,28 +85,6 @@ namespace gl
void init() void init()
{ {
//Check for ARB_shader_draw_parameters
//While it is possible to draw text without full multidraw support, issuing separate draw calls per character is not effecient
int ext_count;
glGetIntegerv(GL_NUM_EXTENSIONS, &ext_count);
for (int i = 0; i < ext_count; i++)
{
const char *ext = (const char*)glGetStringi(GL_EXTENSIONS, i);
if (std::string(ext) == "GL_ARB_shader_draw_parameters")
{
enabled = true;
break;
}
}
if (!enabled)
{
LOG_ERROR(RSX, "Debug overlay could not start because ARB_shader_draw_parameters is not supported by your GPU");
return;
}
m_text_buffer.create(); m_text_buffer.create();
m_scale_offsets_buffer.create(); m_scale_offsets_buffer.create();
@ -136,6 +114,11 @@ namespace gl
init_program(); init_program();
initialized = true; initialized = true;
}
void set_enabled(bool state)
{
enabled = state;
} }
void print_text(int x, int y, int target_w, int target_h, const std::string &text, color4f color = { 0.3f, 1.f, 0.3f, 1.f }) void print_text(int x, int y, int target_w, int target_h, const std::string &text, color4f color = { 0.3f, 1.f, 0.3f, 1.f })
@ -221,4 +204,4 @@ namespace gl
} }
} }
}; };
} }

View file

@ -205,7 +205,7 @@ namespace gl
void reset(const u32 base, const u32 size, const bool flushable) void reset(const u32 base, const u32 size, const bool flushable)
{ {
rsx::buffered_section::reset(base, size); rsx::buffered_section::reset(base, size);
if (flushable) if (flushable)
init_buffer(); init_buffer();
@ -278,7 +278,12 @@ namespace gl
glPixelStorei(GL_PACK_SWAP_BYTES, pack_unpack_swap_bytes); glPixelStorei(GL_PACK_SWAP_BYTES, pack_unpack_swap_bytes);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id); glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_id);
glGetTextureImageEXT(vram_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr);
if (get_driver_caps().EXT_dsa_supported)
glGetTextureImageEXT(vram_texture, GL_TEXTURE_2D, 0, (GLenum)format, (GLenum)type, nullptr);
else
glGetTextureImage(vram_texture, 0, (GLenum)format, (GLenum)type, pbo_size, nullptr);
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
m_fence.reset(); m_fence.reset();
@ -706,7 +711,7 @@ namespace gl
LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err); LOG_WARNING(RSX, "Failed to copy image subresource with GL error 0x%X", err);
return 0; return 0;
} }
return dst_id; return dst_id;
} }
@ -1313,4 +1318,4 @@ namespace gl
return true; return true;
} }
}; };
} }