mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2024-11-01 16:05:07 +01:00
Merge pull request #4613 from BreadFish64/gles5
video_core: add GLES support
This commit is contained in:
commit
f409342ab5
2
externals/glad/Readme.md
vendored
2
externals/glad/Readme.md
vendored
@ -1,5 +1,5 @@
|
||||
These files were generated by the [glad](https://github.com/Dav1dde/glad) OpenGL loader generator and have been checked in as-is. You can re-generate them using glad with the following command:
|
||||
|
||||
```
|
||||
python -m glad --profile core --out-path glad/ --api gl=3.3 --generator=c
|
||||
python -m glad --profile core --out-path glad/ --api "gl=3.3,gles2=3.2" --generator=c
|
||||
```
|
||||
|
16
externals/glad/include/KHR/khrplatform.h
vendored
16
externals/glad/include/KHR/khrplatform.h
vendored
@ -2,7 +2,7 @@
|
||||
#define __khrplatform_h_
|
||||
|
||||
/*
|
||||
** Copyright (c) 2008-2009 The Khronos Group Inc.
|
||||
** Copyright (c) 2008-2018 The Khronos Group Inc.
|
||||
**
|
||||
** Permission is hereby granted, free of charge, to any person obtaining a
|
||||
** copy of this software and/or associated documentation files (the
|
||||
@ -26,18 +26,16 @@
|
||||
|
||||
/* Khronos platform-specific types and definitions.
|
||||
*
|
||||
* $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
|
||||
* The master copy of khrplatform.h is maintained in the Khronos EGL
|
||||
* Registry repository at https://github.com/KhronosGroup/EGL-Registry
|
||||
* The last semantic modification to khrplatform.h was at commit ID:
|
||||
* 67a3e0864c2d75ea5287b9f3d2eb74a745936692
|
||||
*
|
||||
* Adopters may modify this file to suit their platform. Adopters are
|
||||
* encouraged to submit platform specific modifications to the Khronos
|
||||
* group so that they can be included in future versions of this file.
|
||||
* Please submit changes by sending them to the public Khronos Bugzilla
|
||||
* (http://khronos.org/bugzilla) by filing a bug against product
|
||||
* "Khronos (general)" component "Registry".
|
||||
*
|
||||
* A predefined template which fills in some of the bug fields can be
|
||||
* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
|
||||
* must create a Bugzilla login first.
|
||||
* Please submit changes by filing pull requests or issues on
|
||||
* the EGL Registry repository linked above.
|
||||
*
|
||||
*
|
||||
* See the Implementer's Guidelines for information about where this file
|
||||
|
5649
externals/glad/include/glad/glad.h
vendored
5649
externals/glad/include/glad/glad.h
vendored
File diff suppressed because one or more lines are too long
4756
externals/glad/src/glad.c
vendored
4756
externals/glad/src/glad.c
vendored
File diff suppressed because one or more lines are too long
@ -105,6 +105,7 @@ void Config::ReadValues() {
|
||||
Settings::values.use_cpu_jit = sdl2_config->GetBoolean("Core", "use_cpu_jit", true);
|
||||
|
||||
// Renderer
|
||||
Settings::values.use_gles = sdl2_config->GetBoolean("Renderer", "use_gles", false);
|
||||
Settings::values.use_hw_renderer = sdl2_config->GetBoolean("Renderer", "use_hw_renderer", true);
|
||||
#ifdef __APPLE__
|
||||
// Hardware shader is broken on macos thanks to poor drivers.
|
||||
|
@ -92,6 +92,10 @@ udp_pad_index=
|
||||
use_cpu_jit =
|
||||
|
||||
[Renderer]
|
||||
# Whether to render using GLES or OpenGL
|
||||
# 0 (default): OpenGL, 1: GLES
|
||||
use_gles =
|
||||
|
||||
# Whether to use software or hardware rendering.
|
||||
# 0: Software, 1 (default): Hardware
|
||||
use_hw_renderer =
|
||||
|
@ -122,8 +122,13 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
SDL_SetMainReady();
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
if (Settings::values.use_gles) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||
} else {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
}
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
|
||||
@ -155,7 +160,9 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||
auto gl_load_func = Settings::values.use_gles ? gladLoadGLES2Loader : gladLoadGLLoader;
|
||||
|
||||
if (!gl_load_func(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) {
|
||||
LOG_CRITICAL(Frontend, "Failed to initialize GL functions: {}", SDL_GetError());
|
||||
exit(1);
|
||||
}
|
||||
|
@ -67,6 +67,7 @@ void LogSetting(const std::string& name, const T& value) {
|
||||
void LogSettings() {
|
||||
LOG_INFO(Config, "Citra Configuration:");
|
||||
LogSetting("Core_UseCpuJit", Settings::values.use_cpu_jit);
|
||||
LogSetting("Renderer_UseGLES", Settings::values.use_gles);
|
||||
LogSetting("Renderer_UseHwRenderer", Settings::values.use_hw_renderer);
|
||||
LogSetting("Renderer_UseHwShader", Settings::values.use_hw_shader);
|
||||
LogSetting("Renderer_ShadersAccurateGs", Settings::values.shaders_accurate_gs);
|
||||
|
@ -130,6 +130,7 @@ struct Values {
|
||||
u64 init_time;
|
||||
|
||||
// Renderer
|
||||
bool use_gles;
|
||||
bool use_hw_renderer;
|
||||
bool use_hw_shader;
|
||||
bool shaders_accurate_gs;
|
||||
|
@ -41,6 +41,8 @@ add_library(video_core STATIC
|
||||
renderer_opengl/gl_state.h
|
||||
renderer_opengl/gl_stream_buffer.cpp
|
||||
renderer_opengl/gl_stream_buffer.h
|
||||
renderer_opengl/gl_vars.cpp
|
||||
renderer_opengl/gl_vars.h
|
||||
renderer_opengl/pica_to_gl.h
|
||||
renderer_opengl/renderer_opengl.cpp
|
||||
renderer_opengl/renderer_opengl.h
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/utils.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
@ -50,6 +51,17 @@ static constexpr std::array<FormatTuple, 5> fb_format_tuples = {{
|
||||
{GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4
|
||||
}};
|
||||
|
||||
// Same as above, with minor changes for OpenGL ES. Replaced
|
||||
// GL_UNSIGNED_INT_8_8_8_8 with GL_UNSIGNED_BYTE and
|
||||
// GL_BGR with GL_RGB
|
||||
static constexpr std::array<FormatTuple, 5> fb_format_tuples_oes = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE}, // RGBA8
|
||||
{GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE}, // RGB8
|
||||
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1}, // RGB5A1
|
||||
{GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5}, // RGB565
|
||||
{GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4}, // RGBA4
|
||||
}};
|
||||
|
||||
static constexpr std::array<FormatTuple, 4> depth_format_tuples = {{
|
||||
{GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT}, // D16
|
||||
{},
|
||||
@ -63,6 +75,9 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
|
||||
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
|
||||
if (type == SurfaceType::Color) {
|
||||
ASSERT(static_cast<std::size_t>(pixel_format) < fb_format_tuples.size());
|
||||
if (GLES) {
|
||||
return fb_format_tuples_oes[static_cast<unsigned int>(pixel_format)];
|
||||
}
|
||||
return fb_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
|
||||
std::size_t tuple_idx = static_cast<std::size_t>(pixel_format) - 14;
|
||||
@ -72,6 +87,77 @@ static const FormatTuple& GetFormatTuple(PixelFormat pixel_format) {
|
||||
return tex_tuple;
|
||||
}
|
||||
|
||||
/**
|
||||
* OpenGL ES does not support glGetTexImage. Obtain the pixels by attaching the
|
||||
* texture to a framebuffer.
|
||||
* Originally from https://github.com/apitrace/apitrace/blob/master/retrace/glstate_images.cpp
|
||||
*/
|
||||
static inline void GetTexImageOES(GLenum target, GLint level, GLenum format, GLenum type,
|
||||
GLint height, GLint width, GLint depth, GLubyte* pixels) {
|
||||
|
||||
memset(pixels, 0x80, height * width * 4);
|
||||
|
||||
GLenum texture_binding = GL_NONE;
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
texture_binding = GL_TEXTURE_BINDING_2D;
|
||||
break;
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
texture_binding = GL_TEXTURE_BINDING_CUBE_MAP;
|
||||
break;
|
||||
case GL_TEXTURE_3D_OES:
|
||||
texture_binding = GL_TEXTURE_BINDING_3D_OES;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
GLint texture = 0;
|
||||
glGetIntegerv(texture_binding, &texture);
|
||||
if (!texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLint prev_fbo = 0;
|
||||
GLuint fbo = 0;
|
||||
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prev_fbo);
|
||||
glGenFramebuffers(1, &fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
|
||||
|
||||
switch (target) {
|
||||
case GL_TEXTURE_2D:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
|
||||
case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
|
||||
case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: {
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, level);
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
LOG_DEBUG(Render_OpenGL, "Framebuffer is incomplete, status: {:X}", status);
|
||||
}
|
||||
glReadPixels(0, 0, width, height, format, type, pixels);
|
||||
break;
|
||||
}
|
||||
case GL_TEXTURE_3D_OES:
|
||||
for (int i = 0; i < depth; i++) {
|
||||
glFramebufferTexture3D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture,
|
||||
level, i);
|
||||
glReadPixels(0, 0, width, height, format, type, pixels + 4 * i * width * height);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, prev_fbo);
|
||||
|
||||
glDeleteFramebuffers(1, &fbo);
|
||||
}
|
||||
|
||||
template <typename Map, typename Interval>
|
||||
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||
return boost::make_iterator_range(map.equal_range(interval));
|
||||
@ -841,7 +927,12 @@ void CachedSurface::DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLui
|
||||
state.Apply();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]);
|
||||
if (GLES) {
|
||||
GetTexImageOES(GL_TEXTURE_2D, 0, tuple.format, tuple.type, height, width, 0,
|
||||
&gl_buffer[buffer_offset]);
|
||||
} else {
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, tuple.format, tuple.type, &gl_buffer[buffer_offset]);
|
||||
}
|
||||
} else {
|
||||
state.ResetTexture(texture.handle);
|
||||
state.draw.read_framebuffer = read_fb_handle;
|
||||
@ -982,16 +1073,15 @@ RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
||||
d24s8_abgr_buffer.Create();
|
||||
d24s8_abgr_buffer_size = 0;
|
||||
|
||||
const char* vs_source = R"(
|
||||
#version 330 core
|
||||
std::string vs_source = R"(
|
||||
const vec2 vertices[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0));
|
||||
void main() {
|
||||
gl_Position = vec4(vertices[gl_VertexID], 0.0, 1.0);
|
||||
}
|
||||
)";
|
||||
const char* fs_source = R"(
|
||||
#version 330 core
|
||||
|
||||
std::string fs_source = GLES ? fragment_shader_precision_OES : "";
|
||||
fs_source += R"(
|
||||
uniform samplerBuffer tbo;
|
||||
uniform vec2 tbo_size;
|
||||
uniform vec4 viewport;
|
||||
@ -1004,7 +1094,7 @@ void main() {
|
||||
color = texelFetch(tbo, tbo_offset).rabg;
|
||||
}
|
||||
)";
|
||||
d24s8_abgr_shader.Create(vs_source, fs_source);
|
||||
d24s8_abgr_shader.Create(vs_source.c_str(), fs_source.c_str());
|
||||
|
||||
OpenGLState state = OpenGLState::GetCurState();
|
||||
GLuint old_program = state.draw.shader_program;
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
using Pica::FramebufferRegs;
|
||||
@ -1250,7 +1251,6 @@ std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_sh
|
||||
const auto& state = config.state;
|
||||
|
||||
std::string out = R"(
|
||||
#version 330 core
|
||||
#extension GL_ARB_shader_image_load_store : enable
|
||||
#extension GL_ARB_shader_image_size : enable
|
||||
#define ALLOW_SHADOW (defined(GL_ARB_shader_image_load_store) && defined(GL_ARB_shader_image_size))
|
||||
@ -1260,10 +1260,16 @@ std::string GenerateFragmentShader(const PicaFSConfig& config, bool separable_sh
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||
}
|
||||
|
||||
if (GLES) {
|
||||
out += fragment_shader_precision_OES;
|
||||
}
|
||||
|
||||
out += GetVertexInterfaceDeclaration(false, separable_shader);
|
||||
|
||||
out += R"(
|
||||
#ifndef CITRA_GLES
|
||||
in vec4 gl_FragCoord;
|
||||
#endif // CITRA_GLES
|
||||
|
||||
out vec4 color;
|
||||
|
||||
@ -1300,13 +1306,13 @@ float LookupLightingLUT(int lut_index, int index, float delta) {
|
||||
|
||||
float LookupLightingLUTUnsigned(int lut_index, float pos) {
|
||||
int index = clamp(int(pos * 256.0), 0, 255);
|
||||
float delta = pos * 256.0 - index;
|
||||
float delta = pos * 256.0 - float(index);
|
||||
return LookupLightingLUT(lut_index, index, delta);
|
||||
}
|
||||
|
||||
float LookupLightingLUTSigned(int lut_index, float pos) {
|
||||
int index = clamp(int(pos * 128.0), -128, 127);
|
||||
float delta = pos * 128.0 - index;
|
||||
float delta = pos * 128.0 - float(index);
|
||||
if (index < 0) index += 256;
|
||||
return LookupLightingLUT(lut_index, index, delta);
|
||||
}
|
||||
@ -1492,10 +1498,10 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||
// Negate the condition if we have to keep only the pixels outside the scissor box
|
||||
if (state.scissor_test_mode == RasterizerRegs::ScissorMode::Include)
|
||||
out += "!";
|
||||
out += "(gl_FragCoord.x >= scissor_x1 && "
|
||||
"gl_FragCoord.y >= scissor_y1 && "
|
||||
"gl_FragCoord.x < scissor_x2 && "
|
||||
"gl_FragCoord.y < scissor_y2)) discard;\n";
|
||||
out += "(gl_FragCoord.x >= float(scissor_x1) && "
|
||||
"gl_FragCoord.y >= float(scissor_y1) && "
|
||||
"gl_FragCoord.x < float(scissor_x2) && "
|
||||
"gl_FragCoord.y < float(scissor_y2))) discard;\n";
|
||||
}
|
||||
|
||||
// After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
|
||||
@ -1527,7 +1533,7 @@ vec4 secondary_fragment_color = vec4(0.0);
|
||||
if (state.fog_mode == TexturingRegs::FogMode::Fog) {
|
||||
// Get index into fog LUT
|
||||
if (state.fog_flip) {
|
||||
out += "float fog_index = (1.0 - depth) * 128.0;\n";
|
||||
out += "float fog_index = (1.0 - float(depth)) * 128.0;\n";
|
||||
} else {
|
||||
out += "float fog_index = depth * 128.0;\n";
|
||||
}
|
||||
@ -1589,7 +1595,7 @@ do {
|
||||
}
|
||||
|
||||
std::string GenerateTrivialVertexShader(bool separable_shader) {
|
||||
std::string out = "#version 330 core\n";
|
||||
std::string out = "";
|
||||
if (separable_shader) {
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||
}
|
||||
@ -1624,8 +1630,10 @@ void main() {
|
||||
normquat = vert_normquat;
|
||||
view = vert_view;
|
||||
gl_Position = vert_position;
|
||||
#if !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)
|
||||
gl_ClipDistance[0] = -vert_position.z; // fixed PICA clipping plane z <= 0
|
||||
gl_ClipDistance[1] = dot(clip_coef, vert_position);
|
||||
#endif // !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)
|
||||
}
|
||||
)";
|
||||
|
||||
@ -1634,7 +1642,7 @@ void main() {
|
||||
|
||||
std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
|
||||
const PicaVSConfig& config, bool separable_shader) {
|
||||
std::string out = "#version 330 core\n";
|
||||
std::string out = "";
|
||||
if (separable_shader) {
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||
}
|
||||
@ -1742,9 +1750,12 @@ struct Vertex {
|
||||
semantic(VSOutputAttributes::POSITION_Y) + ", " +
|
||||
semantic(VSOutputAttributes::POSITION_Z) + ", " +
|
||||
semantic(VSOutputAttributes::POSITION_W) + ");\n";
|
||||
semantic(VSOutputAttributes::POSITION_W) + ");\n";
|
||||
out += " gl_Position = vtx_pos;\n";
|
||||
out += "#if !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)\n";
|
||||
out += " gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0
|
||||
out += " gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n\n";
|
||||
out += " gl_ClipDistance[1] = dot(clip_coef, vtx_pos);\n";
|
||||
out += "#endif // !defined(CITRA_GLES) || defined(GL_EXT_clip_cull_distance)\n\n";
|
||||
|
||||
out += " vec4 vtx_quat = GetVertexQuaternion(vtx);\n";
|
||||
out += " normquat = mix(vtx_quat, -vtx_quat, bvec4(quats_opposite));\n\n";
|
||||
@ -1787,7 +1798,7 @@ void EmitPrim(Vertex vtx0, Vertex vtx1, Vertex vtx2) {
|
||||
};
|
||||
|
||||
std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config, bool separable_shader) {
|
||||
std::string out = "#version 330 core\n";
|
||||
std::string out = "";
|
||||
if (separable_shader) {
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
}
|
||||
@ -1822,7 +1833,7 @@ void main() {
|
||||
std::optional<std::string> GenerateGeometryShader(const Pica::Shader::ShaderSetup& setup,
|
||||
const PicaGSConfig& config,
|
||||
bool separable_shader) {
|
||||
std::string out = "#version 330 core\n";
|
||||
std::string out = "";
|
||||
if (separable_shader) {
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n";
|
||||
}
|
||||
|
@ -2,15 +2,33 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glad/glad.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
GLuint LoadShader(const char* source, GLenum type) {
|
||||
const std::string version = GLES ? R"(
|
||||
#version 310 es
|
||||
|
||||
#define CITRA_GLES
|
||||
|
||||
#if defined(GL_ANDROID_extension_pack_es31a)
|
||||
#extension GL_ANDROID_extension_pack_es31a : enable
|
||||
#endif // defined(GL_ANDROID_extension_pack_es31a)
|
||||
|
||||
#if defined(GL_EXT_clip_cull_distance)
|
||||
#extension GL_EXT_clip_cull_distance : enable
|
||||
#endif // defined(GL_EXT_clip_cull_distance)
|
||||
)"
|
||||
: "#version 330\n";
|
||||
|
||||
const char* debug_type;
|
||||
switch (type) {
|
||||
case GL_VERTEX_SHADER:
|
||||
@ -26,8 +44,9 @@ GLuint LoadShader(const char* source, GLenum type) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
std::array<const char*, 2> src_arr{version.data(), source};
|
||||
GLuint shader_id = glCreateShader(type);
|
||||
glShaderSource(shader_id, 1, &source, nullptr);
|
||||
glShaderSource(shader_id, static_cast<GLsizei>(src_arr.size()), src_arr.data(), nullptr);
|
||||
LOG_DEBUG(Render_OpenGL, "Compiling {} shader...", debug_type);
|
||||
glCompileShader(shader_id);
|
||||
|
||||
@ -44,7 +63,7 @@ GLuint LoadShader(const char* source, GLenum type) {
|
||||
} else {
|
||||
LOG_ERROR(Render_OpenGL, "Error compiling {} shader:\n{}", debug_type,
|
||||
&shader_error[0]);
|
||||
LOG_ERROR(Render_OpenGL, "Shader source code:\n{}", source);
|
||||
LOG_ERROR(Render_OpenGL, "Shader source code:\n{}{}", src_arr[0], src_arr[1]);
|
||||
}
|
||||
}
|
||||
return shader_id;
|
||||
|
@ -9,6 +9,17 @@
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
// High precision may or may not supported in GLES3. If it isn't, use medium precision instead.
|
||||
static constexpr char fragment_shader_precision_OES[] = R"(
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
precision highp float;
|
||||
precision highp samplerBuffer;
|
||||
#else
|
||||
precision mediump float;
|
||||
precision mediump samplerBuffer;
|
||||
#endif // GL_FRAGMENT_PRECISION_HIGH
|
||||
)";
|
||||
|
||||
/**
|
||||
* Utility function to create and compile an OpenGL GLSL shader
|
||||
* @param source String of the GLSL shader program
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
@ -193,8 +194,13 @@ void OpenGLState::Apply() const {
|
||||
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
|
||||
}
|
||||
|
||||
if (logic_op != cur_state.logic_op) {
|
||||
glLogicOp(logic_op);
|
||||
// GLES3 does not support glLogicOp
|
||||
if (!GLES) {
|
||||
if (logic_op != cur_state.logic_op) {
|
||||
glLogicOp(logic_op);
|
||||
}
|
||||
} else {
|
||||
LOG_TRACE(Render_OpenGL, "glLogicOps are unimplemented...");
|
||||
}
|
||||
|
||||
// Textures
|
||||
@ -319,12 +325,14 @@ void OpenGLState::Apply() const {
|
||||
}
|
||||
|
||||
// Clip distance
|
||||
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
|
||||
if (clip_distance[i] != cur_state.clip_distance[i]) {
|
||||
if (clip_distance[i]) {
|
||||
glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
|
||||
} else {
|
||||
glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
|
||||
if (!GLES || GLAD_GL_EXT_clip_cull_distance) {
|
||||
for (size_t i = 0; i < clip_distance.size(); ++i) {
|
||||
if (clip_distance[i] != cur_state.clip_distance[i]) {
|
||||
if (clip_distance[i]) {
|
||||
glEnable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
|
||||
} else {
|
||||
glDisable(GL_CLIP_DISTANCE0 + static_cast<GLenum>(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
src/video_core/renderer_opengl/gl_vars.cpp
Normal file
9
src/video_core/renderer_opengl/gl_vars.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
|
||||
namespace OpenGL {
|
||||
bool GLES;
|
||||
}
|
9
src/video_core/renderer_opengl/gl_vars.h
Normal file
9
src/video_core/renderer_opengl/gl_vars.h
Normal file
@ -0,0 +1,9 @@
|
||||
// Copyright 2019 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace OpenGL {
|
||||
extern bool GLES;
|
||||
}
|
@ -21,14 +21,13 @@
|
||||
#include "core/tracer/recorder.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
static const char vertex_shader[] = R"(
|
||||
#version 150 core
|
||||
|
||||
in vec2 vert_position;
|
||||
in vec2 vert_tex_coord;
|
||||
out vec2 frag_tex_coord;
|
||||
@ -50,8 +49,6 @@ void main() {
|
||||
)";
|
||||
|
||||
static const char fragment_shader[] = R"(
|
||||
#version 150 core
|
||||
|
||||
in vec2 frag_tex_coord;
|
||||
out vec4 color;
|
||||
|
||||
@ -279,7 +276,13 @@ void RendererOpenGL::InitOpenGLObjects() {
|
||||
0.0f);
|
||||
|
||||
// Link shaders and get variable locations
|
||||
shader.Create(vertex_shader, fragment_shader);
|
||||
if (GLES) {
|
||||
std::string frag_source(fragment_shader_precision_OES);
|
||||
frag_source += fragment_shader;
|
||||
shader.Create(vertex_shader, frag_source.data());
|
||||
} else {
|
||||
shader.Create(vertex_shader, fragment_shader);
|
||||
}
|
||||
state.draw.shader_program = shader.handle;
|
||||
state.Apply();
|
||||
uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
|
||||
@ -344,7 +347,7 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
case GPU::Regs::PixelFormat::RGBA8:
|
||||
internal_format = GL_RGBA;
|
||||
texture.gl_format = GL_RGBA;
|
||||
texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
|
||||
texture.gl_type = GLES ? GL_UNSIGNED_BYTE : GL_UNSIGNED_INT_8_8_8_8;
|
||||
break;
|
||||
|
||||
case GPU::Regs::PixelFormat::RGB8:
|
||||
@ -353,7 +356,9 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
|
||||
// mostly everywhere) for words or half-words.
|
||||
// TODO: check how those behave on big-endian processors.
|
||||
internal_format = GL_RGB;
|
||||
texture.gl_format = GL_BGR;
|
||||
|
||||
// GLES Dosen't support BGR , Use RGB instead
|
||||
texture.gl_format = GLES ? GL_RGB : GL_BGR;
|
||||
texture.gl_type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
@ -555,7 +560,7 @@ Core::System::ResultStatus RendererOpenGL::Init() {
|
||||
return Core::System::ResultStatus::ErrorVideoCore_ErrorGenericDrivers;
|
||||
}
|
||||
|
||||
if (!GLAD_GL_VERSION_3_3) {
|
||||
if (!(GLAD_GL_VERSION_3_3 || GLAD_GL_ES_VERSION_3_1)) {
|
||||
return Core::System::ResultStatus::ErrorVideoCore_ErrorBelowGL33;
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "core/settings.h"
|
||||
#include "video_core/pica.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_vars.h"
|
||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
@ -36,6 +37,8 @@ Core::System::ResultStatus Init(EmuWindow& emu_window, Memory::MemorySystem& mem
|
||||
g_memory = &memory;
|
||||
Pica::Init();
|
||||
|
||||
OpenGL::GLES = Settings::values.use_gles;
|
||||
|
||||
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window);
|
||||
Core::System::ResultStatus result = g_renderer->Init();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user