mirror of https://github.com/PCSX2/pcsx2.git
GS/OGL: Fix sampling from cleared targets
And merge GLLoader into GSDeviceOGL while we're at it.
This commit is contained in:
parent
4290c16997
commit
c2786b91ce
|
@ -607,7 +607,6 @@ set(pcsx2GSHeaders
|
||||||
if(USE_OPENGL)
|
if(USE_OPENGL)
|
||||||
list(APPEND pcsx2GSSources
|
list(APPEND pcsx2GSSources
|
||||||
GS/Renderers/OpenGL/GLContext.cpp
|
GS/Renderers/OpenGL/GLContext.cpp
|
||||||
GS/Renderers/OpenGL/GLLoader.cpp
|
|
||||||
GS/Renderers/OpenGL/GLProgram.cpp
|
GS/Renderers/OpenGL/GLProgram.cpp
|
||||||
GS/Renderers/OpenGL/GLShaderCache.cpp
|
GS/Renderers/OpenGL/GLShaderCache.cpp
|
||||||
GS/Renderers/OpenGL/GLState.cpp
|
GS/Renderers/OpenGL/GLState.cpp
|
||||||
|
@ -617,7 +616,6 @@ if(USE_OPENGL)
|
||||||
)
|
)
|
||||||
list(APPEND pcsx2GSHeaders
|
list(APPEND pcsx2GSHeaders
|
||||||
GS/Renderers/OpenGL/GLContext.h
|
GS/Renderers/OpenGL/GLContext.h
|
||||||
GS/Renderers/OpenGL/GLLoader.h
|
|
||||||
GS/Renderers/OpenGL/GLProgram.h
|
GS/Renderers/OpenGL/GLProgram.h
|
||||||
GS/Renderers/OpenGL/GLShaderCache.h
|
GS/Renderers/OpenGL/GLShaderCache.h
|
||||||
GS/Renderers/OpenGL/GLState.h
|
GS/Renderers/OpenGL/GLState.h
|
||||||
|
|
|
@ -1,198 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "PrecompiledHeader.h"
|
|
||||||
|
|
||||||
#include "GS/Renderers/OpenGL/GLLoader.h"
|
|
||||||
#include "GS/GS.h"
|
|
||||||
#include "Host.h"
|
|
||||||
|
|
||||||
#include "glad.h"
|
|
||||||
|
|
||||||
namespace ReplaceGL
|
|
||||||
{
|
|
||||||
void APIENTRY ScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height)
|
|
||||||
{
|
|
||||||
glScissor(left, bottom, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h)
|
|
||||||
{
|
|
||||||
glViewport(GLint(x), GLint(y), GLsizei(w), GLsizei(h));
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY TextureBarrier()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ReplaceGL
|
|
||||||
|
|
||||||
namespace Emulate_DSA
|
|
||||||
{
|
|
||||||
// Texture entry point
|
|
||||||
void APIENTRY BindTextureUnit(GLuint unit, GLuint texture)
|
|
||||||
{
|
|
||||||
glActiveTexture(GL_TEXTURE0 + unit);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY CreateTexture(GLenum target, GLsizei n, GLuint* textures)
|
|
||||||
{
|
|
||||||
glGenTextures(1, textures);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY TextureStorage(GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glTexStorage2D(GL_TEXTURE_2D, levels, internalformat, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY TextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, pixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY CompressedTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glCompressedTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, imageSize, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY GetTexureImage(GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glGetTexImage(GL_TEXTURE_2D, level, format, type, pixels);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY TextureParameteri(GLuint texture, GLenum pname, GLint param)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, pname, param);
|
|
||||||
}
|
|
||||||
|
|
||||||
void APIENTRY GenerateTextureMipmap(GLuint texture)
|
|
||||||
{
|
|
||||||
BindTextureUnit(7, texture);
|
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Misc entry point
|
|
||||||
void APIENTRY CreateSamplers(GLsizei n, GLuint* samplers)
|
|
||||||
{
|
|
||||||
glGenSamplers(n, samplers);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Replace function pointer to emulate DSA behavior
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
glBindTextureUnit = BindTextureUnit;
|
|
||||||
glCreateTextures = CreateTexture;
|
|
||||||
glTextureStorage2D = TextureStorage;
|
|
||||||
glTextureSubImage2D = TextureSubImage;
|
|
||||||
glCompressedTextureSubImage2D = CompressedTextureSubImage;
|
|
||||||
glGetTextureImage = GetTexureImage;
|
|
||||||
glTextureParameteri = TextureParameteri;
|
|
||||||
glGenerateTextureMipmap = GenerateTextureMipmap;
|
|
||||||
glCreateSamplers = CreateSamplers;
|
|
||||||
}
|
|
||||||
} // namespace Emulate_DSA
|
|
||||||
|
|
||||||
namespace GLLoader
|
|
||||||
{
|
|
||||||
bool vendor_id_amd = false;
|
|
||||||
bool vendor_id_nvidia = false;
|
|
||||||
bool vendor_id_intel = false;
|
|
||||||
bool buggy_pbo = false;
|
|
||||||
bool disable_download_pbo = false;
|
|
||||||
|
|
||||||
static bool check_gl_version()
|
|
||||||
{
|
|
||||||
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
|
||||||
if (strstr(vendor, "Advanced Micro Devices") || strstr(vendor, "ATI Technologies Inc.") || strstr(vendor, "ATI"))
|
|
||||||
vendor_id_amd = true;
|
|
||||||
else if (strstr(vendor, "NVIDIA Corporation"))
|
|
||||||
vendor_id_nvidia = true;
|
|
||||||
else if (strstr(vendor, "Intel"))
|
|
||||||
vendor_id_intel = true;
|
|
||||||
|
|
||||||
GLint major_gl = 0;
|
|
||||||
GLint minor_gl = 0;
|
|
||||||
glGetIntegerv(GL_MAJOR_VERSION, &major_gl);
|
|
||||||
glGetIntegerv(GL_MINOR_VERSION, &minor_gl);
|
|
||||||
if (!GLAD_GL_VERSION_3_3 && !GLAD_GL_ES_VERSION_3_1)
|
|
||||||
{
|
|
||||||
Host::ReportFormattedErrorAsync("GS", "OpenGL is not supported. Only OpenGL %d.%d\n was found", major_gl, minor_gl);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool check_gl_supported_extension()
|
|
||||||
{
|
|
||||||
if (!GLAD_GL_ARB_shading_language_420pack)
|
|
||||||
{
|
|
||||||
Host::ReportFormattedErrorAsync("GS",
|
|
||||||
"GL_ARB_shading_language_420pack is not supported, this is required for the OpenGL renderer.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLAD_GL_ARB_viewport_array)
|
|
||||||
{
|
|
||||||
glScissorIndexed = ReplaceGL::ScissorIndexed;
|
|
||||||
glViewportIndexedf = ReplaceGL::ViewportIndexedf;
|
|
||||||
Console.Warning("GL_ARB_viewport_array is not supported! Function pointer will be replaced.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLAD_GL_ARB_texture_barrier)
|
|
||||||
{
|
|
||||||
glTextureBarrier = ReplaceGL::TextureBarrier;
|
|
||||||
Host::AddOSDMessage("GL_ARB_texture_barrier is not supported, blending will not be accurate.",
|
|
||||||
Host::OSD_ERROR_DURATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GLAD_GL_ARB_direct_state_access)
|
|
||||||
{
|
|
||||||
Console.Warning("GL_ARB_direct_state_access is not supported, this will reduce performance.");
|
|
||||||
Emulate_DSA::Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't use PBOs when we don't have ARB_buffer_storage, orphaning buffers probably ends up worse than just
|
|
||||||
// using the normal texture update routines and letting the driver take care of it.
|
|
||||||
buggy_pbo = !GLAD_GL_VERSION_4_4 && !GLAD_GL_ARB_buffer_storage && !GLAD_GL_EXT_buffer_storage;
|
|
||||||
if (buggy_pbo)
|
|
||||||
Console.Warning("Not using PBOs for texture uploads because buffer_storage is unavailable.");
|
|
||||||
|
|
||||||
// Give the user the option to disable PBO usage for downloads.
|
|
||||||
// Most drivers seem to be faster with PBO.
|
|
||||||
disable_download_pbo = Host::GetBoolSettingValue("EmuCore/GS", "DisableGLDownloadPBO", false);
|
|
||||||
if (disable_download_pbo)
|
|
||||||
Console.Warning("Not using PBOs for texture downloads, this may reduce performance.");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check_gl_requirements()
|
|
||||||
{
|
|
||||||
if (!check_gl_version())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!check_gl_supported_extension())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // namespace GLLoader
|
|
|
@ -1,27 +0,0 @@
|
||||||
/* PCSX2 - PS2 Emulator for PCs
|
|
||||||
* Copyright (C) 2002-2021 PCSX2 Dev Team
|
|
||||||
*
|
|
||||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
||||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
||||||
* ation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
||||||
* PURPOSE. See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
||||||
* If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace GLLoader
|
|
||||||
{
|
|
||||||
bool check_gl_requirements();
|
|
||||||
|
|
||||||
extern bool vendor_id_amd;
|
|
||||||
extern bool vendor_id_nvidia;
|
|
||||||
extern bool vendor_id_intel;
|
|
||||||
extern bool buggy_pbo;
|
|
||||||
extern bool disable_download_pbo;
|
|
||||||
} // namespace GLLoader
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GS/Renderers/OpenGL/GLLoader.h"
|
|
||||||
#include "GS/GSVector.h"
|
#include "GS/GSVector.h"
|
||||||
|
|
||||||
#include "glad.h"
|
#include "glad.h"
|
||||||
|
|
|
@ -41,7 +41,98 @@ static constexpr u32 VERTEX_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024;
|
||||||
static constexpr u32 FRAGMENT_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024;
|
static constexpr u32 FRAGMENT_UNIFORM_BUFFER_SIZE = 8 * 1024 * 1024;
|
||||||
static constexpr u32 TEXTURE_UPLOAD_BUFFER_SIZE = 128 * 1024 * 1024;
|
static constexpr u32 TEXTURE_UPLOAD_BUFFER_SIZE = 128 * 1024 * 1024;
|
||||||
|
|
||||||
static std::unique_ptr<GLStreamBuffer> s_texture_upload_buffer;
|
namespace ReplaceGL
|
||||||
|
{
|
||||||
|
static void APIENTRY ScissorIndexed(GLuint index, GLint left, GLint bottom, GLsizei width, GLsizei height)
|
||||||
|
{
|
||||||
|
glScissor(left, bottom, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY ViewportIndexedf(GLuint index, GLfloat x, GLfloat y, GLfloat w, GLfloat h)
|
||||||
|
{
|
||||||
|
glViewport(GLint(x), GLint(y), GLsizei(w), GLsizei(h));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY TextureBarrier()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ReplaceGL
|
||||||
|
|
||||||
|
namespace Emulate_DSA
|
||||||
|
{
|
||||||
|
// Texture entry point
|
||||||
|
static void APIENTRY BindTextureUnit(GLuint unit, GLuint texture)
|
||||||
|
{
|
||||||
|
glActiveTexture(GL_TEXTURE0 + unit);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY CreateTexture(GLenum target, GLsizei n, GLuint* textures)
|
||||||
|
{
|
||||||
|
glGenTextures(1, textures);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY TextureStorage(
|
||||||
|
GLuint texture, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glTexStorage2D(GL_TEXTURE_2D, levels, internalformat, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY TextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
|
||||||
|
GLsizei height, GLenum format, GLenum type, const void* pixels)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, type, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY CompressedTextureSubImage(GLuint texture, GLint level, GLint xoffset, GLint yoffset,
|
||||||
|
GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glCompressedTexSubImage2D(GL_TEXTURE_2D, level, xoffset, yoffset, width, height, format, imageSize, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GetTexureImage(
|
||||||
|
GLuint texture, GLint level, GLenum format, GLenum type, GLsizei bufSize, void* pixels)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glGetTexImage(GL_TEXTURE_2D, level, format, type, pixels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY TextureParameteri(GLuint texture, GLenum pname, GLint param)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, pname, param);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void APIENTRY GenerateTextureMipmap(GLuint texture)
|
||||||
|
{
|
||||||
|
BindTextureUnit(7, texture);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Misc entry point
|
||||||
|
static void APIENTRY CreateSamplers(GLsizei n, GLuint* samplers)
|
||||||
|
{
|
||||||
|
glGenSamplers(n, samplers);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replace function pointer to emulate DSA behavior
|
||||||
|
static void Init()
|
||||||
|
{
|
||||||
|
glBindTextureUnit = BindTextureUnit;
|
||||||
|
glCreateTextures = CreateTexture;
|
||||||
|
glTextureStorage2D = TextureStorage;
|
||||||
|
glTextureSubImage2D = TextureSubImage;
|
||||||
|
glCompressedTextureSubImage2D = CompressedTextureSubImage;
|
||||||
|
glGetTextureImage = GetTexureImage;
|
||||||
|
glTextureParameteri = TextureParameteri;
|
||||||
|
glGenerateTextureMipmap = GenerateTextureMipmap;
|
||||||
|
glCreateSamplers = CreateSamplers;
|
||||||
|
}
|
||||||
|
} // namespace Emulate_DSA
|
||||||
|
|
||||||
GSDeviceOGL::GSDeviceOGL() = default;
|
GSDeviceOGL::GSDeviceOGL() = default;
|
||||||
|
|
||||||
|
@ -96,7 +187,6 @@ bool GSDeviceOGL::Create()
|
||||||
if (!m_gl_context)
|
if (!m_gl_context)
|
||||||
{
|
{
|
||||||
Console.Error("Failed to create any GL context");
|
Console.Error("Failed to create any GL context");
|
||||||
m_gl_context.reset();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,15 +196,16 @@ bool GSDeviceOGL::Create()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render a frame as soon as possible to clear out whatever was previously being displayed.
|
bool buggy_pbo;
|
||||||
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
if (!CheckFeatures(buggy_pbo))
|
||||||
RenderBlankFrame();
|
|
||||||
|
|
||||||
if (!GLLoader::check_gl_requirements())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SetSwapInterval();
|
SetSwapInterval();
|
||||||
|
|
||||||
|
// Render a frame as soon as possible to clear out whatever was previously being displayed.
|
||||||
|
if (m_window_info.type != WindowInfo::Type::Surfaceless)
|
||||||
|
RenderBlankFrame();
|
||||||
|
|
||||||
if (!GSConfig.DisableShaderCache)
|
if (!GSConfig.DisableShaderCache)
|
||||||
{
|
{
|
||||||
if (!m_shader_cache.Open())
|
if (!m_shader_cache.Open())
|
||||||
|
@ -125,68 +216,6 @@ bool GSDeviceOGL::Create()
|
||||||
Console.WriteLn("Not using shader cache.");
|
Console.WriteLn("Not using shader cache.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional features based on context
|
|
||||||
m_features.broken_point_sampler = GLLoader::vendor_id_amd;
|
|
||||||
m_features.primitive_id = true;
|
|
||||||
|
|
||||||
m_features.framebuffer_fetch = GLAD_GL_EXT_shader_framebuffer_fetch;
|
|
||||||
if (m_features.framebuffer_fetch && GSConfig.DisableFramebufferFetch)
|
|
||||||
{
|
|
||||||
Host::AddOSDMessage("Framebuffer fetch was found but is disabled. This will reduce performance.", Host::OSD_ERROR_DURATION);
|
|
||||||
m_features.framebuffer_fetch = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GSConfig.OverrideTextureBarriers == 0)
|
|
||||||
m_features.texture_barrier = m_features.framebuffer_fetch; // Force Disabled
|
|
||||||
else if (GSConfig.OverrideTextureBarriers == 1)
|
|
||||||
m_features.texture_barrier = true; // Force Enabled
|
|
||||||
else
|
|
||||||
m_features.texture_barrier = m_features.framebuffer_fetch || GLAD_GL_ARB_texture_barrier;
|
|
||||||
if (!m_features.texture_barrier)
|
|
||||||
{
|
|
||||||
Host::AddOSDMessage(
|
|
||||||
"GL_ARB_texture_barrier is not supported, blending will not be accurate.", Host::OSD_ERROR_DURATION);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_features.provoking_vertex_last = true;
|
|
||||||
m_features.dxt_textures = GLAD_GL_EXT_texture_compression_s3tc;
|
|
||||||
m_features.bptc_textures = GLAD_GL_VERSION_4_2 || GLAD_GL_ARB_texture_compression_bptc || GLAD_GL_EXT_texture_compression_bptc;
|
|
||||||
m_features.prefer_new_textures = false;
|
|
||||||
m_features.dual_source_blend = !GSConfig.DisableDualSourceBlend;
|
|
||||||
m_features.clip_control = GLAD_GL_ARB_clip_control;
|
|
||||||
if (!m_features.clip_control)
|
|
||||||
Host::AddOSDMessage("GL_ARB_clip_control is not supported, this will cause rendering issues.", Host::OSD_ERROR_DURATION);
|
|
||||||
m_features.stencil_buffer = true;
|
|
||||||
m_features.test_and_sample_depth = m_features.texture_barrier;
|
|
||||||
|
|
||||||
// NVIDIA GPUs prior to Kepler appear to have broken vertex shader buffer loading.
|
|
||||||
// Use bindless textures (introduced in Kepler) to differentiate.
|
|
||||||
const bool buggy_vs_expand =
|
|
||||||
GLLoader::vendor_id_nvidia && (!GLAD_GL_ARB_bindless_texture && !GLAD_GL_NV_bindless_texture);
|
|
||||||
if (buggy_vs_expand)
|
|
||||||
Console.Warning("Disabling vertex shader expand due to broken NVIDIA driver.");
|
|
||||||
|
|
||||||
if (GLAD_GL_ARB_shader_storage_buffer_object)
|
|
||||||
{
|
|
||||||
GLint max_vertex_ssbos = 0;
|
|
||||||
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max_vertex_ssbos);
|
|
||||||
DevCon.WriteLn("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: %d", max_vertex_ssbos);
|
|
||||||
m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && !buggy_vs_expand && max_vertex_ssbos > 0 &&
|
|
||||||
GLAD_GL_ARB_gpu_shader5);
|
|
||||||
}
|
|
||||||
if (!m_features.vs_expand)
|
|
||||||
Console.Warning("Vertex expansion is not supported. This will reduce performance.");
|
|
||||||
|
|
||||||
GLint point_range[2] = {};
|
|
||||||
glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_range);
|
|
||||||
m_features.point_expand = (point_range[0] <= GSConfig.UpscaleMultiplier && point_range[1] >= GSConfig.UpscaleMultiplier);
|
|
||||||
m_features.line_expand = false;
|
|
||||||
|
|
||||||
Console.WriteLn("Using %s for point expansion, %s for line expansion and %s for sprite expansion.",
|
|
||||||
m_features.point_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),
|
|
||||||
m_features.line_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),
|
|
||||||
m_features.vs_expand ? "vertex expanding" : "CPU");
|
|
||||||
|
|
||||||
// because of fbo bindings below...
|
// because of fbo bindings below...
|
||||||
GLState::Clear();
|
GLState::Clear();
|
||||||
|
|
||||||
|
@ -512,19 +541,18 @@ bool GSDeviceOGL::Create()
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
// Pbo Pool allocation
|
// Pbo Pool allocation
|
||||||
// ****************************************************************
|
// ****************************************************************
|
||||||
if (!GLLoader::buggy_pbo)
|
if (!buggy_pbo)
|
||||||
{
|
{
|
||||||
s_texture_upload_buffer = GLStreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_UPLOAD_BUFFER_SIZE);
|
m_texture_upload_buffer = GLStreamBuffer::Create(GL_PIXEL_UNPACK_BUFFER, TEXTURE_UPLOAD_BUFFER_SIZE);
|
||||||
if (s_texture_upload_buffer)
|
if (m_texture_upload_buffer)
|
||||||
{
|
{
|
||||||
// Don't keep it bound, we'll re-bind when we need it.
|
// Don't keep it bound, we'll re-bind when we need it.
|
||||||
// Otherwise non-PBO texture uploads break. Yay for global state.
|
// Otherwise non-PBO texture uploads break. Yay for global state.
|
||||||
s_texture_upload_buffer->Unbind();
|
m_texture_upload_buffer->Unbind();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.Error("Failed to create texture upload buffer. Using slow path.");
|
Console.Error("Failed to create texture upload buffer. Using slow path.");
|
||||||
GLLoader::buggy_pbo = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -587,6 +615,176 @@ bool GSDeviceOGL::CreateTextureFX()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GSDeviceOGL::CheckFeatures(bool& buggy_pbo)
|
||||||
|
{
|
||||||
|
bool vendor_id_amd = false;
|
||||||
|
bool vendor_id_nvidia = false;
|
||||||
|
bool vendor_id_intel = false;
|
||||||
|
|
||||||
|
const char* vendor = (const char*)glGetString(GL_VENDOR);
|
||||||
|
if (std::strstr(vendor, "Advanced Micro Devices") || std::strstr(vendor, "ATI Technologies Inc.") ||
|
||||||
|
std::strstr(vendor, "ATI"))
|
||||||
|
{
|
||||||
|
Console.WriteLn(Color_StrongRed, "OGL: AMD GPU detected.");
|
||||||
|
vendor_id_amd = true;
|
||||||
|
}
|
||||||
|
else if (std::strstr(vendor, "NVIDIA Corporation"))
|
||||||
|
{
|
||||||
|
Console.WriteLn(Color_StrongGreen, "OGL: NVIDIA GPU detected.");
|
||||||
|
vendor_id_nvidia = true;
|
||||||
|
}
|
||||||
|
else if (std::strstr(vendor, "Intel"))
|
||||||
|
{
|
||||||
|
Console.WriteLn(Color_StrongBlue, "OGL: Intel GPU detected.");
|
||||||
|
vendor_id_intel = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint major_gl = 0;
|
||||||
|
GLint minor_gl = 0;
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major_gl);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor_gl);
|
||||||
|
if (!GLAD_GL_VERSION_3_3)
|
||||||
|
{
|
||||||
|
Host::ReportErrorAsync(
|
||||||
|
"GS", fmt::format("OpenGL renderer is not supported. Only OpenGL {}.{}\n was found", major_gl, minor_gl));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log extension string for debugging purposes.
|
||||||
|
Console.WriteLn(fmt::format("GL_VENDOR: {}", reinterpret_cast<const char*>(glGetString(GL_VENDOR))));
|
||||||
|
Console.WriteLn(fmt::format("GL_VERSION: {}", reinterpret_cast<const char*>(glGetString(GL_VERSION))));
|
||||||
|
Console.WriteLn(fmt::format("GL_RENDERER: {}", reinterpret_cast<const char*>(glGetString(GL_RENDERER))));
|
||||||
|
Console.WriteLn(fmt::format(
|
||||||
|
"GL_SHADING_LANGUAGE_VERSION: {}", reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION))));
|
||||||
|
std::string extensions = "GL_EXTENSIONS:";
|
||||||
|
GLint num_extensions = 0;
|
||||||
|
glGetIntegerv(GL_NUM_EXTENSIONS, &num_extensions);
|
||||||
|
for (GLint i = 0; i < num_extensions; i++)
|
||||||
|
{
|
||||||
|
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||||
|
if (ext)
|
||||||
|
{
|
||||||
|
extensions += ' ';
|
||||||
|
extensions.append(ext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLn(std::move(extensions));
|
||||||
|
|
||||||
|
if (!GLAD_GL_ARB_shading_language_420pack)
|
||||||
|
{
|
||||||
|
Host::ReportFormattedErrorAsync(
|
||||||
|
"GS", "GL_ARB_shading_language_420pack is not supported, this is required for the OpenGL renderer.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLAD_GL_VERSION_4_3 && !GLAD_GL_ARB_copy_image && !GLAD_GL_EXT_copy_image)
|
||||||
|
{
|
||||||
|
Host::ReportFormattedErrorAsync(
|
||||||
|
"GS", "GL_ARB_copy_image is not supported, this is required for the OpenGL renderer.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLAD_GL_ARB_viewport_array)
|
||||||
|
{
|
||||||
|
glScissorIndexed = ReplaceGL::ScissorIndexed;
|
||||||
|
glViewportIndexedf = ReplaceGL::ViewportIndexedf;
|
||||||
|
Console.Warning("GL_ARB_viewport_array is not supported! Function pointer will be replaced.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLAD_GL_ARB_texture_barrier)
|
||||||
|
{
|
||||||
|
glTextureBarrier = ReplaceGL::TextureBarrier;
|
||||||
|
Host::AddOSDMessage(
|
||||||
|
"GL_ARB_texture_barrier is not supported, blending will not be accurate.", Host::OSD_ERROR_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GLAD_GL_ARB_direct_state_access)
|
||||||
|
{
|
||||||
|
Console.Warning("GL_ARB_direct_state_access is not supported, this will reduce performance.");
|
||||||
|
Emulate_DSA::Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't use PBOs when we don't have ARB_buffer_storage, orphaning buffers probably ends up worse than just
|
||||||
|
// using the normal texture update routines and letting the driver take care of it.
|
||||||
|
buggy_pbo = !GLAD_GL_VERSION_4_4 && !GLAD_GL_ARB_buffer_storage && !GLAD_GL_EXT_buffer_storage;
|
||||||
|
if (buggy_pbo)
|
||||||
|
Console.Warning("Not using PBOs for texture uploads because buffer_storage is unavailable.");
|
||||||
|
|
||||||
|
// Give the user the option to disable PBO usage for downloads.
|
||||||
|
// Most drivers seem to be faster with PBO.
|
||||||
|
m_disable_download_pbo = Host::GetBoolSettingValue("EmuCore/GS", "DisableGLDownloadPBO", false);
|
||||||
|
if (m_disable_download_pbo)
|
||||||
|
Console.Warning("Not using PBOs for texture downloads, this may reduce performance.");
|
||||||
|
|
||||||
|
// optional features based on context
|
||||||
|
m_features.broken_point_sampler = vendor_id_amd;
|
||||||
|
m_features.primitive_id = true;
|
||||||
|
|
||||||
|
m_features.framebuffer_fetch = GLAD_GL_EXT_shader_framebuffer_fetch;
|
||||||
|
if (m_features.framebuffer_fetch && GSConfig.DisableFramebufferFetch)
|
||||||
|
{
|
||||||
|
Host::AddOSDMessage(
|
||||||
|
"Framebuffer fetch was found but is disabled. This will reduce performance.", Host::OSD_ERROR_DURATION);
|
||||||
|
m_features.framebuffer_fetch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GSConfig.OverrideTextureBarriers == 0)
|
||||||
|
m_features.texture_barrier = m_features.framebuffer_fetch; // Force Disabled
|
||||||
|
else if (GSConfig.OverrideTextureBarriers == 1)
|
||||||
|
m_features.texture_barrier = true; // Force Enabled
|
||||||
|
else
|
||||||
|
m_features.texture_barrier = m_features.framebuffer_fetch || GLAD_GL_ARB_texture_barrier;
|
||||||
|
if (!m_features.texture_barrier)
|
||||||
|
{
|
||||||
|
Host::AddOSDMessage(
|
||||||
|
"GL_ARB_texture_barrier is not supported, blending will not be accurate.", Host::OSD_ERROR_DURATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_features.provoking_vertex_last = true;
|
||||||
|
m_features.dxt_textures = GLAD_GL_EXT_texture_compression_s3tc;
|
||||||
|
m_features.bptc_textures =
|
||||||
|
GLAD_GL_VERSION_4_2 || GLAD_GL_ARB_texture_compression_bptc || GLAD_GL_EXT_texture_compression_bptc;
|
||||||
|
m_features.prefer_new_textures = false;
|
||||||
|
m_features.dual_source_blend = !GSConfig.DisableDualSourceBlend;
|
||||||
|
m_features.clip_control = GLAD_GL_ARB_clip_control;
|
||||||
|
if (!m_features.clip_control)
|
||||||
|
Host::AddOSDMessage(
|
||||||
|
"GL_ARB_clip_control is not supported, this will cause rendering issues.", Host::OSD_ERROR_DURATION);
|
||||||
|
m_features.stencil_buffer = true;
|
||||||
|
m_features.test_and_sample_depth = m_features.texture_barrier;
|
||||||
|
|
||||||
|
// NVIDIA GPUs prior to Kepler appear to have broken vertex shader buffer loading.
|
||||||
|
// Use bindless textures (introduced in Kepler) to differentiate.
|
||||||
|
const bool buggy_vs_expand =
|
||||||
|
vendor_id_nvidia && (!GLAD_GL_ARB_bindless_texture && !GLAD_GL_NV_bindless_texture);
|
||||||
|
if (buggy_vs_expand)
|
||||||
|
Console.Warning("Disabling vertex shader expand due to broken NVIDIA driver.");
|
||||||
|
|
||||||
|
if (GLAD_GL_ARB_shader_storage_buffer_object)
|
||||||
|
{
|
||||||
|
GLint max_vertex_ssbos = 0;
|
||||||
|
glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &max_vertex_ssbos);
|
||||||
|
DevCon.WriteLn("GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS: %d", max_vertex_ssbos);
|
||||||
|
m_features.vs_expand = (!GSConfig.DisableVertexShaderExpand && !buggy_vs_expand && max_vertex_ssbos > 0 &&
|
||||||
|
GLAD_GL_ARB_gpu_shader5);
|
||||||
|
}
|
||||||
|
if (!m_features.vs_expand)
|
||||||
|
Console.Warning("Vertex expansion is not supported. This will reduce performance.");
|
||||||
|
|
||||||
|
GLint point_range[2] = {};
|
||||||
|
glGetIntegerv(GL_ALIASED_POINT_SIZE_RANGE, point_range);
|
||||||
|
m_features.point_expand =
|
||||||
|
(point_range[0] <= GSConfig.UpscaleMultiplier && point_range[1] >= GSConfig.UpscaleMultiplier);
|
||||||
|
m_features.line_expand = false;
|
||||||
|
|
||||||
|
Console.WriteLn("Using %s for point expansion, %s for line expansion and %s for sprite expansion.",
|
||||||
|
m_features.point_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),
|
||||||
|
m_features.line_expand ? "hardware" : (m_features.vs_expand ? "vertex expanding" : "UNSUPPORTED"),
|
||||||
|
m_features.vs_expand ? "vertex expanding" : "CPU");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void GSDeviceOGL::SetSwapInterval()
|
void GSDeviceOGL::SetSwapInterval()
|
||||||
{
|
{
|
||||||
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
|
const int interval = ((m_vsync_mode == VsyncMode::Adaptive) ? -1 : ((m_vsync_mode == VsyncMode::On) ? 1 : 0));
|
||||||
|
@ -648,7 +846,7 @@ void GSDeviceOGL::DestroyResources()
|
||||||
|
|
||||||
m_index_stream_buffer.reset();
|
m_index_stream_buffer.reset();
|
||||||
m_vertex_stream_buffer.reset();
|
m_vertex_stream_buffer.reset();
|
||||||
s_texture_upload_buffer.reset();
|
m_texture_upload_buffer.reset();
|
||||||
if (m_expand_ibo)
|
if (m_expand_ibo)
|
||||||
glDeleteBuffers(1, &m_expand_ibo);
|
glDeleteBuffers(1, &m_expand_ibo);
|
||||||
|
|
||||||
|
@ -1230,10 +1428,6 @@ void GSDeviceOGL::BlitRect(GSTexture* sTex, const GSVector4i& r, const GSVector2
|
||||||
// Copy a sub part of a texture into another
|
// Copy a sub part of a texture into another
|
||||||
void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
|
void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r, u32 destX, u32 destY)
|
||||||
{
|
{
|
||||||
ASSERT(sTex && dTex);
|
|
||||||
if (!(sTex && dTex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
|
const GLuint& sid = static_cast<GSTextureOGL*>(sTex)->GetID();
|
||||||
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
|
const GLuint& did = static_cast<GSTextureOGL*>(dTex)->GetID();
|
||||||
CommitClear(sTex, false);
|
CommitClear(sTex, false);
|
||||||
|
@ -1253,26 +1447,6 @@ void GSDeviceOGL::CopyRect(GSTexture* sTex, GSTexture* dTex, const GSVector4i& r
|
||||||
glCopyImageSubDataEXT(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
|
glCopyImageSubDataEXT(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
|
||||||
0, destX, destY, 0, r.width(), r.height(), 1);
|
0, destX, destY, 0, r.width(), r.height(), 1);
|
||||||
}
|
}
|
||||||
else if (GLAD_GL_OES_copy_image)
|
|
||||||
{
|
|
||||||
glCopyImageSubDataOES(sid, GL_TEXTURE_2D, 0, r.x, r.y, 0, did, GL_TEXTURE_2D,
|
|
||||||
0, destX, destY, 0, r.width(), r.height(), 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo_read);
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo_write);
|
|
||||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, sid, 0);
|
|
||||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, did, 0);
|
|
||||||
|
|
||||||
const int w = r.width(), h = r.height();
|
|
||||||
glDisable(GL_SCISSOR_TEST);
|
|
||||||
glBlitFramebuffer(r.x, r.y, r.x + w, r.y + h, destX + r.x, destY + r.y, destX + r.x + w, destY + r.y + h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
|
||||||
glEnable(GL_SCISSOR_TEST);
|
|
||||||
|
|
||||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLState::fbo);
|
|
||||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
|
void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader, bool linear)
|
||||||
|
@ -1774,23 +1948,14 @@ void GSDeviceOGL::IASetPrimitiveTopology(GLenum topology)
|
||||||
|
|
||||||
void GSDeviceOGL::PSSetShaderResource(int i, GSTexture* sr)
|
void GSDeviceOGL::PSSetShaderResource(int i, GSTexture* sr)
|
||||||
{
|
{
|
||||||
ASSERT(i < static_cast<int>(std::size(GLState::tex_unit)));
|
pxAssert(i < static_cast<int>(std::size(GLState::tex_unit)));
|
||||||
// Note: Nvidia debgger doesn't support the id 0 (ie the NULL texture)
|
|
||||||
if (sr)
|
|
||||||
{
|
|
||||||
const GLuint id = static_cast<GSTextureOGL*>(sr)->GetID();
|
|
||||||
if (GLState::tex_unit[i] != id)
|
|
||||||
{
|
|
||||||
GLState::tex_unit[i] = id;
|
|
||||||
glBindTextureUnit(i, id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GSDeviceOGL::PSSetShaderResources(GSTexture* sr0, GSTexture* sr1)
|
const GLuint id = static_cast<GSTextureOGL*>(sr)->GetID();
|
||||||
{
|
if (GLState::tex_unit[i] != id)
|
||||||
PSSetShaderResource(0, sr0);
|
{
|
||||||
PSSetShaderResource(1, sr1);
|
GLState::tex_unit[i] = id;
|
||||||
|
glBindTextureUnit(i, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GSDeviceOGL::PSSetSamplerState(GLuint ss)
|
void GSDeviceOGL::PSSetSamplerState(GLuint ss)
|
||||||
|
@ -2216,6 +2381,11 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||||
GLState::scissor = config.scissor;
|
GLState::scissor = config.scissor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (config.tex)
|
||||||
|
CommitClear(config.tex, true);
|
||||||
|
if (config.pal)
|
||||||
|
CommitClear(config.pal, true);
|
||||||
|
|
||||||
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
GSVector2i rtsize = (config.rt ? config.rt : config.ds)->GetSize();
|
||||||
|
|
||||||
GSTexture* primid_texture = nullptr;
|
GSTexture* primid_texture = nullptr;
|
||||||
|
@ -2308,7 +2478,10 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
|
||||||
}
|
}
|
||||||
IASetPrimitiveTopology(topology);
|
IASetPrimitiveTopology(topology);
|
||||||
|
|
||||||
PSSetShaderResources(config.tex, config.pal);
|
if (config.tex)
|
||||||
|
PSSetShaderResource(0, config.tex);
|
||||||
|
if (config.pal)
|
||||||
|
PSSetShaderResource(1, config.pal);
|
||||||
if (draw_rt_clone)
|
if (draw_rt_clone)
|
||||||
PSSetShaderResource(2, draw_rt_clone);
|
PSSetShaderResource(2, draw_rt_clone);
|
||||||
else if (config.require_one_barrier || config.require_full_barrier)
|
else if (config.require_one_barrier || config.require_full_barrier)
|
||||||
|
@ -2584,11 +2757,6 @@ void GSDeviceOGL::DebugMessageCallback(GLenum gl_source, GLenum gl_type, GLuint
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GLStreamBuffer* GSDeviceOGL::GetTextureUploadBuffer()
|
|
||||||
{
|
|
||||||
return s_texture_upload_buffer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GSDeviceOGL::PushDebugGroup(const char* fmt, ...)
|
void GSDeviceOGL::PushDebugGroup(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_OGL_DEBUG
|
#ifdef ENABLE_OGL_DEBUG
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GS/Renderers/Common/GSDevice.h"
|
#include "GS/Renderers/Common/GSDevice.h"
|
||||||
#include "GS/Renderers/OpenGL/GLLoader.h"
|
|
||||||
#include "GS/Renderers/OpenGL/GLProgram.h"
|
#include "GS/Renderers/OpenGL/GLProgram.h"
|
||||||
#include "GS/Renderers/OpenGL/GLShaderCache.h"
|
#include "GS/Renderers/OpenGL/GLShaderCache.h"
|
||||||
#include "GS/Renderers/OpenGL/GLState.h"
|
#include "GS/Renderers/OpenGL/GLState.h"
|
||||||
|
@ -154,10 +153,14 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<GLContext> m_gl_context;
|
std::unique_ptr<GLContext> m_gl_context;
|
||||||
|
|
||||||
|
bool m_disable_download_pbo = false;
|
||||||
|
|
||||||
GLuint m_fbo = 0; // frame buffer container
|
GLuint m_fbo = 0; // frame buffer container
|
||||||
GLuint m_fbo_read = 0; // frame buffer container only for reading
|
GLuint m_fbo_read = 0; // frame buffer container only for reading
|
||||||
GLuint m_fbo_write = 0; // frame buffer container only for writing
|
GLuint m_fbo_write = 0; // frame buffer container only for writing
|
||||||
|
|
||||||
|
std::unique_ptr<GLStreamBuffer> m_texture_upload_buffer;
|
||||||
|
|
||||||
std::unique_ptr<GLStreamBuffer> m_vertex_stream_buffer;
|
std::unique_ptr<GLStreamBuffer> m_vertex_stream_buffer;
|
||||||
std::unique_ptr<GLStreamBuffer> m_index_stream_buffer;
|
std::unique_ptr<GLStreamBuffer> m_index_stream_buffer;
|
||||||
GLuint m_expand_ibo = 0;
|
GLuint m_expand_ibo = 0;
|
||||||
|
@ -240,6 +243,8 @@ private:
|
||||||
std::string m_shader_tfx_vgs;
|
std::string m_shader_tfx_vgs;
|
||||||
std::string m_shader_tfx_fs;
|
std::string m_shader_tfx_fs;
|
||||||
|
|
||||||
|
bool CheckFeatures(bool& buggy_pbo);
|
||||||
|
|
||||||
void SetSwapInterval();
|
void SetSwapInterval();
|
||||||
void DestroyResources();
|
void DestroyResources();
|
||||||
|
|
||||||
|
@ -281,10 +286,10 @@ public:
|
||||||
// Used by OpenGL, so the same calling convention is required.
|
// Used by OpenGL, so the same calling convention is required.
|
||||||
static void APIENTRY DebugMessageCallback(GLenum gl_source, GLenum gl_type, GLuint id, GLenum gl_severity, GLsizei gl_length, const GLchar* gl_message, const void* userParam);
|
static void APIENTRY DebugMessageCallback(GLenum gl_source, GLenum gl_type, GLuint id, GLenum gl_severity, GLsizei gl_length, const GLchar* gl_message, const void* userParam);
|
||||||
|
|
||||||
static GLStreamBuffer* GetTextureUploadBuffer();
|
__fi bool IsDownloadPBODisabled() const { return m_disable_download_pbo; }
|
||||||
|
|
||||||
__fi u32 GetFBORead() const { return m_fbo_read; }
|
__fi u32 GetFBORead() const { return m_fbo_read; }
|
||||||
__fi u32 GetFBOWrite() const { return m_fbo_write; }
|
__fi u32 GetFBOWrite() const { return m_fbo_write; }
|
||||||
|
__fi GLStreamBuffer* GetTextureUploadBuffer() const { return m_texture_upload_buffer.get(); }
|
||||||
void CommitClear(GSTexture* t, bool use_write_fbo);
|
void CommitClear(GSTexture* t, bool use_write_fbo);
|
||||||
|
|
||||||
RenderAPI GetRenderAPI() const override;
|
RenderAPI GetRenderAPI() const override;
|
||||||
|
@ -346,7 +351,6 @@ public:
|
||||||
void IASetIndexBuffer(const void* index, size_t count);
|
void IASetIndexBuffer(const void* index, size_t count);
|
||||||
|
|
||||||
void PSSetShaderResource(int i, GSTexture* sr);
|
void PSSetShaderResource(int i, GSTexture* sr);
|
||||||
void PSSetShaderResources(GSTexture* sr0, GSTexture* sr1);
|
|
||||||
void PSSetSamplerState(GLuint ss);
|
void PSSetSamplerState(GLuint ss);
|
||||||
void ClearSamplerCache() override;
|
void ClearSamplerCache() override;
|
||||||
|
|
||||||
|
|
|
@ -214,6 +214,7 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int
|
||||||
|
|
||||||
// Don't use PBOs for huge texture uploads, let the driver sort it out.
|
// Don't use PBOs for huge texture uploads, let the driver sort it out.
|
||||||
// Otherwise we'll just be syncing, or worse, crashing because the PBO routine above isn't great.
|
// Otherwise we'll just be syncing, or worse, crashing because the PBO routine above isn't great.
|
||||||
|
GLStreamBuffer* const sb = GSDeviceOGL::GetInstance()->GetTextureUploadBuffer();
|
||||||
if (IsCompressedFormat())
|
if (IsCompressedFormat())
|
||||||
{
|
{
|
||||||
const u32 row_length = CalcUploadRowLengthFromPitch(pitch);
|
const u32 row_length = CalcUploadRowLengthFromPitch(pitch);
|
||||||
|
@ -222,7 +223,7 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int
|
||||||
glCompressedTextureSubImage2D(m_texture_id, layer, r.x, r.y, r.width(), r.height(), m_int_format, upload_size, data);
|
glCompressedTextureSubImage2D(m_texture_id, layer, r.x, r.y, r.width(), r.height(), m_int_format, upload_size, data);
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
}
|
}
|
||||||
else if (GLLoader::buggy_pbo || map_size > GSDeviceOGL::GetTextureUploadBuffer()->GetChunkSize())
|
else if (!sb || map_size > sb->GetChunkSize())
|
||||||
{
|
{
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> m_int_shift);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> m_int_shift);
|
||||||
glTextureSubImage2D(m_texture_id, layer, r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, data);
|
glTextureSubImage2D(m_texture_id, layer, r.x, r.y, r.width(), r.height(), m_int_format, m_int_type, data);
|
||||||
|
@ -230,8 +231,6 @@ bool GSTextureOGL::Update(const GSVector4i& r, const void* data, int pitch, int
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GLStreamBuffer* const sb = GSDeviceOGL::GetTextureUploadBuffer();
|
|
||||||
|
|
||||||
const auto map = sb->Map(TEXTURE_UPLOAD_ALIGNMENT, map_size);
|
const auto map = sb->Map(TEXTURE_UPLOAD_ALIGNMENT, map_size);
|
||||||
StringUtil::StrideMemCpy(map.pointer, preferred_pitch, data, pitch, r.width() << m_int_shift, r.height());
|
StringUtil::StrideMemCpy(map.pointer, preferred_pitch, data, pitch, r.width() << m_int_shift, r.height());
|
||||||
sb->Unmap(map_size);
|
sb->Unmap(map_size);
|
||||||
|
@ -271,13 +270,14 @@ bool GSTextureOGL::Map(GSMap& m, const GSVector4i* _r, int layer)
|
||||||
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
if (m_type == Type::Texture || m_type == Type::RenderTarget)
|
||||||
{
|
{
|
||||||
const u32 upload_size = CalcUploadSize(r.height(), pitch);
|
const u32 upload_size = CalcUploadSize(r.height(), pitch);
|
||||||
if (GLLoader::buggy_pbo || upload_size > GSDeviceOGL::GetTextureUploadBuffer()->GetChunkSize())
|
GLStreamBuffer* sb = GSDeviceOGL::GetInstance()->GetTextureUploadBuffer();
|
||||||
|
if (!sb || upload_size > sb->GetChunkSize())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
GL_PUSH_("Upload Texture %d", m_texture_id); // POP is in Unmap
|
GL_PUSH_("Upload Texture %d", m_texture_id); // POP is in Unmap
|
||||||
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
g_perfmon.Put(GSPerfMon::TextureUploads, 1);
|
||||||
|
|
||||||
const auto map = GSDeviceOGL::GetTextureUploadBuffer()->Map(TEXTURE_UPLOAD_ALIGNMENT, upload_size);
|
const auto map = sb->Map(TEXTURE_UPLOAD_ALIGNMENT, upload_size);
|
||||||
m.bits = static_cast<u8*>(map.pointer);
|
m.bits = static_cast<u8*>(map.pointer);
|
||||||
|
|
||||||
// Save the area for the unmap
|
// Save the area for the unmap
|
||||||
|
@ -302,7 +302,7 @@ void GSTextureOGL::Unmap()
|
||||||
|
|
||||||
const u32 pitch = Common::AlignUpPow2(m_r_w << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
const u32 pitch = Common::AlignUpPow2(m_r_w << m_int_shift, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||||
const u32 upload_size = pitch * m_r_h;
|
const u32 upload_size = pitch * m_r_h;
|
||||||
GLStreamBuffer* sb = GSDeviceOGL::GetTextureUploadBuffer();
|
GLStreamBuffer* sb = GSDeviceOGL::GetInstance()->GetTextureUploadBuffer();
|
||||||
sb->Unmap(upload_size);
|
sb->Unmap(upload_size);
|
||||||
sb->Bind();
|
sb->Bind();
|
||||||
|
|
||||||
|
@ -435,7 +435,7 @@ std::unique_ptr<GSDownloadTextureOGL> GSDownloadTextureOGL::Create(u32 width, u3
|
||||||
const u32 buffer_size = GetBufferSize(width, height, format, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
const u32 buffer_size = GetBufferSize(width, height, format, TEXTURE_UPLOAD_PITCH_ALIGNMENT);
|
||||||
|
|
||||||
const bool use_buffer_storage = (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage) &&
|
const bool use_buffer_storage = (GLAD_GL_VERSION_4_4 || GLAD_GL_ARB_buffer_storage || GLAD_GL_EXT_buffer_storage) &&
|
||||||
!GLLoader::disable_download_pbo;
|
!GSDeviceOGL::GetInstance()->IsDownloadPBODisabled();
|
||||||
if (use_buffer_storage)
|
if (use_buffer_storage)
|
||||||
{
|
{
|
||||||
GLuint buffer_id;
|
GLuint buffer_id;
|
||||||
|
|
|
@ -16,7 +16,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "GS/Renderers/Common/GSTexture.h"
|
#include "GS/Renderers/Common/GSTexture.h"
|
||||||
#include "GS/Renderers/OpenGL/GLLoader.h"
|
|
||||||
|
#include "glad.h"
|
||||||
|
|
||||||
class GSTextureOGL final : public GSTexture
|
class GSTextureOGL final : public GSTexture
|
||||||
{
|
{
|
||||||
|
|
|
@ -267,7 +267,6 @@
|
||||||
<ClCompile Include="Dmac.cpp" />
|
<ClCompile Include="Dmac.cpp" />
|
||||||
<ClCompile Include="ShiftJisToUnicode.cpp" />
|
<ClCompile Include="ShiftJisToUnicode.cpp" />
|
||||||
<ClCompile Include="sif2.cpp" />
|
<ClCompile Include="sif2.cpp" />
|
||||||
<ClCompile Include="GS\Renderers\OpenGL\GLLoader.cpp" />
|
|
||||||
<ClCompile Include="GS\Renderers\OpenGL\GLState.cpp" />
|
<ClCompile Include="GS\Renderers\OpenGL\GLState.cpp" />
|
||||||
<ClCompile Include="GS\GS.cpp" />
|
<ClCompile Include="GS\GS.cpp" />
|
||||||
<ClCompile Include="GS\GSAlignedClass.cpp" />
|
<ClCompile Include="GS\GSAlignedClass.cpp" />
|
||||||
|
@ -607,7 +606,6 @@
|
||||||
<ClInclude Include="SPU2\regs.h" />
|
<ClInclude Include="SPU2\regs.h" />
|
||||||
<ClInclude Include="SPU2\Mixer.h" />
|
<ClInclude Include="SPU2\Mixer.h" />
|
||||||
<ClInclude Include="SPU2\spu2.h" />
|
<ClInclude Include="SPU2\spu2.h" />
|
||||||
<ClInclude Include="GS\Renderers\OpenGL\GLLoader.h" />
|
|
||||||
<ClInclude Include="GS\Renderers\OpenGL\GLState.h" />
|
<ClInclude Include="GS\Renderers\OpenGL\GLState.h" />
|
||||||
<ClInclude Include="GS\GS.h" />
|
<ClInclude Include="GS\GS.h" />
|
||||||
<ClInclude Include="GS\GSExtra.h" />
|
<ClInclude Include="GS\GSExtra.h" />
|
||||||
|
|
|
@ -1034,9 +1034,6 @@
|
||||||
<ClCompile Include="GS\Renderers\DX11\GSTextureFX11.cpp">
|
<ClCompile Include="GS\Renderers\DX11\GSTextureFX11.cpp">
|
||||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="GS\Renderers\OpenGL\GLLoader.cpp">
|
|
||||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="GS\Renderers\OpenGL\GSDeviceOGL.cpp">
|
<ClCompile Include="GS\Renderers\OpenGL\GSDeviceOGL.cpp">
|
||||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
@ -1981,9 +1978,6 @@
|
||||||
<ClInclude Include="GS\Renderers\DX11\GSTexture11.h">
|
<ClInclude Include="GS\Renderers\DX11\GSTexture11.h">
|
||||||
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
<Filter>System\Ps2\GS\Renderers\Direct3D11</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="GS\Renderers\OpenGL\GLLoader.h">
|
|
||||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="GS\Renderers\OpenGL\GSDeviceOGL.h">
|
<ClInclude Include="GS\Renderers\OpenGL\GSDeviceOGL.h">
|
||||||
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
<Filter>System\Ps2\GS\Renderers\OpenGL</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
|
Loading…
Reference in New Issue