mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #254 from bunnei/port-citra-renderer
Port Citra OpenGL rasterizer code
This commit is contained in:
		
						commit
						0b3ab30762
					
				
							
								
								
									
										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,gles=3.0
 | 
			
		||||
python -m glad --profile core --out-path glad/ --api gl=3.3 --generator=c
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6
									
								
								externals/glad/include/KHR/khrplatform.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								externals/glad/include/KHR/khrplatform.h
									
									
									
									
										vendored
									
									
								
							@ -26,7 +26,7 @@
 | 
			
		||||
 | 
			
		||||
/* Khronos platform-specific types and definitions.
 | 
			
		||||
 *
 | 
			
		||||
 * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
 | 
			
		||||
 * $Revision: 32517 $ on $Date: 2016-03-11 02:41:19 -0800 (Fri, 11 Mar 2016) $
 | 
			
		||||
 *
 | 
			
		||||
 * Adopters may modify this file to suit their platform. Adopters are
 | 
			
		||||
 * encouraged to submit platform specific modifications to the Khronos
 | 
			
		||||
@ -101,6 +101,8 @@
 | 
			
		||||
#   define KHRONOS_APICALL __declspec(dllimport)
 | 
			
		||||
#elif defined (__SYMBIAN32__)
 | 
			
		||||
#   define KHRONOS_APICALL IMPORT_C
 | 
			
		||||
#elif defined(__ANDROID__)
 | 
			
		||||
#   define KHRONOS_APICALL __attribute__((visibility("default")))
 | 
			
		||||
#else
 | 
			
		||||
#   define KHRONOS_APICALL
 | 
			
		||||
#endif
 | 
			
		||||
@ -223,7 +225,7 @@ typedef signed   short int     khronos_int16_t;
 | 
			
		||||
typedef unsigned short int     khronos_uint16_t;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Types that differ between LLP64 and LP64 architectures - in LLP64, 
 | 
			
		||||
 * Types that differ between LLP64 and LP64 architectures - in LLP64,
 | 
			
		||||
 * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
 | 
			
		||||
 * to be the only LLP64 architecture in current use.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13755
									
								
								externals/glad/include/glad/glad.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										13755
									
								
								externals/glad/include/glad/glad.h
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										8704
									
								
								externals/glad/src/glad.c
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8704
									
								
								externals/glad/src/glad.c
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -11,13 +11,24 @@ add_library(video_core STATIC
 | 
			
		||||
    gpu.h
 | 
			
		||||
    memory_manager.cpp
 | 
			
		||||
    memory_manager.h
 | 
			
		||||
    rasterizer_interface.h
 | 
			
		||||
    renderer_base.cpp
 | 
			
		||||
    renderer_base.h
 | 
			
		||||
    renderer_opengl/gl_rasterizer.cpp
 | 
			
		||||
    renderer_opengl/gl_rasterizer.h
 | 
			
		||||
    renderer_opengl/gl_rasterizer_cache.cpp
 | 
			
		||||
    renderer_opengl/gl_rasterizer_cache.h
 | 
			
		||||
    renderer_opengl/gl_resource_manager.h
 | 
			
		||||
    renderer_opengl/gl_shader_decompiler.cpp
 | 
			
		||||
    renderer_opengl/gl_shader_decompiler.h
 | 
			
		||||
    renderer_opengl/gl_shader_gen.cpp
 | 
			
		||||
    renderer_opengl/gl_shader_gen.h
 | 
			
		||||
    renderer_opengl/gl_shader_util.cpp
 | 
			
		||||
    renderer_opengl/gl_shader_util.h
 | 
			
		||||
    renderer_opengl/gl_state.cpp
 | 
			
		||||
    renderer_opengl/gl_state.h
 | 
			
		||||
    renderer_opengl/gl_stream_buffer.cpp
 | 
			
		||||
    renderer_opengl/gl_stream_buffer.h
 | 
			
		||||
    renderer_opengl/renderer_opengl.cpp
 | 
			
		||||
    renderer_opengl/renderer_opengl.h
 | 
			
		||||
    utils.h
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										61
									
								
								src/video_core/rasterizer_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/video_core/rasterizer_interface.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
// Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
struct ScreenInfo;
 | 
			
		||||
 | 
			
		||||
namespace VideoCore {
 | 
			
		||||
 | 
			
		||||
class RasterizerInterface {
 | 
			
		||||
public:
 | 
			
		||||
    virtual ~RasterizerInterface() {}
 | 
			
		||||
 | 
			
		||||
    /// Draw the current batch of triangles
 | 
			
		||||
    virtual void DrawTriangles() = 0;
 | 
			
		||||
 | 
			
		||||
    /// Notify rasterizer that the specified Maxwell register has been changed
 | 
			
		||||
    virtual void NotifyMaxwellRegisterChanged(u32 id) = 0;
 | 
			
		||||
 | 
			
		||||
    /// Notify rasterizer that all caches should be flushed to 3DS memory
 | 
			
		||||
    virtual void FlushAll() = 0;
 | 
			
		||||
 | 
			
		||||
    /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
 | 
			
		||||
    virtual void FlushRegion(PAddr addr, u32 size) = 0;
 | 
			
		||||
 | 
			
		||||
    /// Notify rasterizer that any caches of the specified region should be invalidated
 | 
			
		||||
    virtual void InvalidateRegion(PAddr addr, u32 size) = 0;
 | 
			
		||||
 | 
			
		||||
    /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory
 | 
			
		||||
    /// and invalidated
 | 
			
		||||
    virtual void FlushAndInvalidateRegion(PAddr addr, u32 size) = 0;
 | 
			
		||||
 | 
			
		||||
    /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 0
 | 
			
		||||
    virtual bool AccelerateDisplayTransfer(const void* config) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Attempt to use a faster method to perform a display transfer with is_texture_copy = 1
 | 
			
		||||
    virtual bool AccelerateTextureCopy(const void* config) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Attempt to use a faster method to fill a region
 | 
			
		||||
    virtual bool AccelerateFill(const void* config) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Attempt to use a faster method to display the framebuffer to screen
 | 
			
		||||
    virtual bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride,
 | 
			
		||||
                                   ScreenInfo& screen_info) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual bool AccelerateDrawBatch(bool is_indexed) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
} // namespace VideoCore
 | 
			
		||||
							
								
								
									
										269
									
								
								src/video_core/renderer_opengl/gl_rasterizer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										269
									
								
								src/video_core/renderer_opengl/gl_rasterizer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,269 @@
 | 
			
		||||
// Copyright 2015 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/logging/log.h"
 | 
			
		||||
#include "common/math_util.h"
 | 
			
		||||
#include "common/microprofile.h"
 | 
			
		||||
#include "common/scope_exit.h"
 | 
			
		||||
#include "common/vector_math.h"
 | 
			
		||||
#include "core/settings.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
 | 
			
		||||
#include "video_core/renderer_opengl/renderer_opengl.h"
 | 
			
		||||
 | 
			
		||||
using PixelFormat = SurfaceParams::PixelFormat;
 | 
			
		||||
using SurfaceType = SurfaceParams::SurfaceType;
 | 
			
		||||
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_VS, "OpenGL", "Vertex Shader Setup", MP_RGB(128, 128, 192));
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_FS, "OpenGL", "Fragment Shader Setup", MP_RGB(128, 128, 192));
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
 | 
			
		||||
MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
 | 
			
		||||
 | 
			
		||||
enum class UniformBindings : GLuint { Common, VS, FS };
 | 
			
		||||
 | 
			
		||||
static void SetShaderUniformBlockBinding(GLuint shader, const char* name, UniformBindings binding,
 | 
			
		||||
                                         size_t expected_size) {
 | 
			
		||||
    GLuint ub_index = glGetUniformBlockIndex(shader, name);
 | 
			
		||||
    if (ub_index != GL_INVALID_INDEX) {
 | 
			
		||||
        GLint ub_size = 0;
 | 
			
		||||
        glGetActiveUniformBlockiv(shader, ub_index, GL_UNIFORM_BLOCK_DATA_SIZE, &ub_size);
 | 
			
		||||
        ASSERT_MSG(ub_size == expected_size,
 | 
			
		||||
                   "Uniform block size did not match! Got %d, expected %zu",
 | 
			
		||||
                   static_cast<int>(ub_size), expected_size);
 | 
			
		||||
        glUniformBlockBinding(shader, ub_index, static_cast<GLuint>(binding));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SetShaderUniformBlockBindings(GLuint shader) {
 | 
			
		||||
    SetShaderUniformBlockBinding(shader, "shader_data", UniformBindings::Common,
 | 
			
		||||
                                 sizeof(RasterizerOpenGL::UniformData));
 | 
			
		||||
    SetShaderUniformBlockBinding(shader, "vs_config", UniformBindings::VS,
 | 
			
		||||
                                 sizeof(RasterizerOpenGL::VSUniformData));
 | 
			
		||||
    SetShaderUniformBlockBinding(shader, "fs_config", UniformBindings::FS,
 | 
			
		||||
                                 sizeof(RasterizerOpenGL::FSUniformData));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RasterizerOpenGL::RasterizerOpenGL() {
 | 
			
		||||
    has_ARB_buffer_storage = false;
 | 
			
		||||
    has_ARB_direct_state_access = false;
 | 
			
		||||
    has_ARB_separate_shader_objects = false;
 | 
			
		||||
    has_ARB_vertex_attrib_binding = false;
 | 
			
		||||
 | 
			
		||||
    GLint ext_num;
 | 
			
		||||
    glGetIntegerv(GL_NUM_EXTENSIONS, &ext_num);
 | 
			
		||||
    for (GLint i = 0; i < ext_num; i++) {
 | 
			
		||||
        std::string extension{reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i))};
 | 
			
		||||
 | 
			
		||||
        if (extension == "GL_ARB_buffer_storage") {
 | 
			
		||||
            has_ARB_buffer_storage = true;
 | 
			
		||||
        } else if (extension == "GL_ARB_direct_state_access") {
 | 
			
		||||
            has_ARB_direct_state_access = true;
 | 
			
		||||
        } else if (extension == "GL_ARB_separate_shader_objects") {
 | 
			
		||||
            has_ARB_separate_shader_objects = true;
 | 
			
		||||
        } else if (extension == "GL_ARB_vertex_attrib_binding") {
 | 
			
		||||
            has_ARB_vertex_attrib_binding = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
 | 
			
		||||
    state.clip_distance[0] = true;
 | 
			
		||||
 | 
			
		||||
    // Generate VBO, VAO and UBO
 | 
			
		||||
    vertex_buffer = OGLStreamBuffer::MakeBuffer(GLAD_GL_ARB_buffer_storage, GL_ARRAY_BUFFER);
 | 
			
		||||
    vertex_buffer->Create(VERTEX_BUFFER_SIZE, VERTEX_BUFFER_SIZE / 2);
 | 
			
		||||
    sw_vao.Create();
 | 
			
		||||
    uniform_buffer.Create();
 | 
			
		||||
 | 
			
		||||
    state.draw.vertex_array = sw_vao.handle;
 | 
			
		||||
    state.draw.vertex_buffer = vertex_buffer->GetHandle();
 | 
			
		||||
    state.draw.uniform_buffer = uniform_buffer.handle;
 | 
			
		||||
    state.Apply();
 | 
			
		||||
 | 
			
		||||
    glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), nullptr, GL_STATIC_DRAW);
 | 
			
		||||
    glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle);
 | 
			
		||||
 | 
			
		||||
    uniform_block_data.dirty = true;
 | 
			
		||||
 | 
			
		||||
    // Create render framebuffer
 | 
			
		||||
    framebuffer.Create();
 | 
			
		||||
 | 
			
		||||
    if (has_ARB_separate_shader_objects) {
 | 
			
		||||
        hw_vao.Create();
 | 
			
		||||
        hw_vao_enabled_attributes.fill(false);
 | 
			
		||||
 | 
			
		||||
        stream_buffer = OGLStreamBuffer::MakeBuffer(has_ARB_buffer_storage, GL_ARRAY_BUFFER);
 | 
			
		||||
        stream_buffer->Create(STREAM_BUFFER_SIZE, STREAM_BUFFER_SIZE / 2);
 | 
			
		||||
        state.draw.vertex_buffer = stream_buffer->GetHandle();
 | 
			
		||||
 | 
			
		||||
        pipeline.Create();
 | 
			
		||||
        vs_input_index_min = 0;
 | 
			
		||||
        vs_input_index_max = 0;
 | 
			
		||||
        state.draw.program_pipeline = pipeline.handle;
 | 
			
		||||
        state.draw.shader_program = 0;
 | 
			
		||||
        state.draw.vertex_array = hw_vao.handle;
 | 
			
		||||
        state.Apply();
 | 
			
		||||
 | 
			
		||||
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, stream_buffer->GetHandle());
 | 
			
		||||
 | 
			
		||||
        vs_uniform_buffer.Create();
 | 
			
		||||
        glBindBuffer(GL_UNIFORM_BUFFER, vs_uniform_buffer.handle);
 | 
			
		||||
        glBufferData(GL_UNIFORM_BUFFER, sizeof(VSUniformData), nullptr, GL_STREAM_COPY);
 | 
			
		||||
        glBindBufferBase(GL_UNIFORM_BUFFER, 1, vs_uniform_buffer.handle);
 | 
			
		||||
    } else {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    accelerate_draw = AccelDraw::Disabled;
 | 
			
		||||
 | 
			
		||||
    glEnable(GL_BLEND);
 | 
			
		||||
 | 
			
		||||
    // Sync fixed function OpenGL state
 | 
			
		||||
    SyncClipEnabled();
 | 
			
		||||
    SyncClipCoef();
 | 
			
		||||
    SyncCullMode();
 | 
			
		||||
    SyncBlendEnabled();
 | 
			
		||||
    SyncBlendFuncs();
 | 
			
		||||
    SyncBlendColor();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RasterizerOpenGL::~RasterizerOpenGL() {
 | 
			
		||||
    if (stream_buffer != nullptr) {
 | 
			
		||||
        state.draw.vertex_buffer = stream_buffer->GetHandle();
 | 
			
		||||
        state.Apply();
 | 
			
		||||
        stream_buffer->Release();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static constexpr std::array<GLenum, 4> vs_attrib_types{
 | 
			
		||||
    GL_BYTE,          // VertexAttributeFormat::BYTE
 | 
			
		||||
    GL_UNSIGNED_BYTE, // VertexAttributeFormat::UBYTE
 | 
			
		||||
    GL_SHORT,         // VertexAttributeFormat::SHORT
 | 
			
		||||
    GL_FLOAT          // VertexAttributeFormat::FLOAT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::AnalyzeVertexArray(bool is_indexed) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_VAO);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_VS);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_FS);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDrawBatch(bool is_indexed) {
 | 
			
		||||
    if (!has_ARB_separate_shader_objects) {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    accelerate_draw = is_indexed ? AccelDraw::Indexed : AccelDraw::Arrays;
 | 
			
		||||
    DrawTriangles();
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::DrawTriangles() {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_Drawing);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::NotifyMaxwellRegisterChanged(u32 id) {}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushAll() {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.FlushAll();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.FlushRegion(addr, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.InvalidateRegion(addr, size, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_CacheManagement);
 | 
			
		||||
    res_cache.FlushRegion(addr, size);
 | 
			
		||||
    res_cache.InvalidateRegion(addr, size, nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDisplayTransfer(const void* config) {
 | 
			
		||||
    MICROPROFILE_SCOPE(OpenGL_Blits);
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateTextureCopy(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateFill(const void* config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool RasterizerOpenGL::AccelerateDisplay(const void* config, PAddr framebuffer_addr,
 | 
			
		||||
                                         u32 pixel_stride, ScreenInfo& screen_info) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SetShader() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncClipEnabled() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncClipCoef() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncCullMode() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncDepthScale() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncDepthOffset() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendEnabled() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendFuncs() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RasterizerOpenGL::SyncBlendColor() {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										162
									
								
								src/video_core/renderer_opengl/gl_rasterizer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								src/video_core/renderer_opengl/gl_rasterizer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,162 @@
 | 
			
		||||
// Copyright 2015 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include "common/bit_field.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/hash.h"
 | 
			
		||||
#include "common/vector_math.h"
 | 
			
		||||
#include "video_core/rasterizer_interface.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_state.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
 | 
			
		||||
 | 
			
		||||
struct ScreenInfo;
 | 
			
		||||
 | 
			
		||||
class RasterizerOpenGL : public VideoCore::RasterizerInterface {
 | 
			
		||||
public:
 | 
			
		||||
    RasterizerOpenGL();
 | 
			
		||||
    ~RasterizerOpenGL() override;
 | 
			
		||||
 | 
			
		||||
    void DrawTriangles() override;
 | 
			
		||||
    void NotifyMaxwellRegisterChanged(u32 id) override;
 | 
			
		||||
    void FlushAll() override;
 | 
			
		||||
    void FlushRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    void InvalidateRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
 | 
			
		||||
    bool AccelerateDisplayTransfer(const void* config) override;
 | 
			
		||||
    bool AccelerateTextureCopy(const void* config) override;
 | 
			
		||||
    bool AccelerateFill(const void* config) override;
 | 
			
		||||
    bool AccelerateDisplay(const void* config, PAddr framebuffer_addr, u32 pixel_stride,
 | 
			
		||||
                           ScreenInfo& screen_info) override;
 | 
			
		||||
    bool AccelerateDrawBatch(bool is_indexed) override;
 | 
			
		||||
 | 
			
		||||
    struct VertexShader {
 | 
			
		||||
        OGLShader shader;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct FragmentShader {
 | 
			
		||||
        OGLShader shader;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
 | 
			
		||||
    // NOTE: Always keep a vec4 at the end. The GL spec is not clear wether the alignment at
 | 
			
		||||
    //       the end of a uniform block is included in UNIFORM_BLOCK_DATA_SIZE or not.
 | 
			
		||||
    //       Not following that rule will cause problems on some AMD drivers.
 | 
			
		||||
    struct UniformData {};
 | 
			
		||||
 | 
			
		||||
    // static_assert(
 | 
			
		||||
    //    sizeof(UniformData) == 0x460,
 | 
			
		||||
    //    "The size of the UniformData structure has changed, update the structure in the shader");
 | 
			
		||||
    static_assert(sizeof(UniformData) < 16384,
 | 
			
		||||
                  "UniformData structure must be less than 16kb as per the OpenGL spec");
 | 
			
		||||
 | 
			
		||||
    struct VSUniformData {};
 | 
			
		||||
    // static_assert(
 | 
			
		||||
    //    sizeof(VSUniformData) == 1856,
 | 
			
		||||
    //    "The size of the VSUniformData structure has changed, update the structure in the
 | 
			
		||||
    //    shader");
 | 
			
		||||
    static_assert(sizeof(VSUniformData) < 16384,
 | 
			
		||||
                  "VSUniformData structure must be less than 16kb as per the OpenGL spec");
 | 
			
		||||
 | 
			
		||||
    struct FSUniformData {};
 | 
			
		||||
    // static_assert(
 | 
			
		||||
    //    sizeof(FSUniformData) == 1856,
 | 
			
		||||
    //    "The size of the FSUniformData structure has changed, update the structure in the
 | 
			
		||||
    //    shader");
 | 
			
		||||
    static_assert(sizeof(FSUniformData) < 16384,
 | 
			
		||||
                  "FSUniformData structure must be less than 16kb as per the OpenGL spec");
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct SamplerInfo {};
 | 
			
		||||
 | 
			
		||||
    /// Syncs the clip enabled status to match the guest state
 | 
			
		||||
    void SyncClipEnabled();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the clip coefficients to match the guest state
 | 
			
		||||
    void SyncClipCoef();
 | 
			
		||||
 | 
			
		||||
    /// Sets the OpenGL shader in accordance with the current guest state
 | 
			
		||||
    void SetShader();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the cull mode to match the guest state
 | 
			
		||||
    void SyncCullMode();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the depth scale to match the guest state
 | 
			
		||||
    void SyncDepthScale();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the depth offset to match the guest state
 | 
			
		||||
    void SyncDepthOffset();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the blend enabled status to match the guest state
 | 
			
		||||
    void SyncBlendEnabled();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the blend functions to match the guest state
 | 
			
		||||
    void SyncBlendFuncs();
 | 
			
		||||
 | 
			
		||||
    /// Syncs the blend color to match the guest state
 | 
			
		||||
    void SyncBlendColor();
 | 
			
		||||
 | 
			
		||||
    bool has_ARB_buffer_storage;
 | 
			
		||||
    bool has_ARB_direct_state_access;
 | 
			
		||||
    bool has_ARB_separate_shader_objects;
 | 
			
		||||
    bool has_ARB_vertex_attrib_binding;
 | 
			
		||||
 | 
			
		||||
    OpenGLState state;
 | 
			
		||||
 | 
			
		||||
    RasterizerCacheOpenGL res_cache;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        UniformData data;
 | 
			
		||||
        bool dirty;
 | 
			
		||||
    } uniform_block_data = {};
 | 
			
		||||
 | 
			
		||||
    OGLPipeline pipeline;
 | 
			
		||||
    OGLVertexArray sw_vao;
 | 
			
		||||
    OGLVertexArray hw_vao;
 | 
			
		||||
    std::array<bool, 16> hw_vao_enabled_attributes;
 | 
			
		||||
 | 
			
		||||
    std::array<SamplerInfo, 3> texture_samplers;
 | 
			
		||||
    static constexpr size_t VERTEX_BUFFER_SIZE = 128 * 1024 * 1024;
 | 
			
		||||
    std::unique_ptr<OGLStreamBuffer> vertex_buffer;
 | 
			
		||||
    OGLBuffer uniform_buffer;
 | 
			
		||||
    OGLFramebuffer framebuffer;
 | 
			
		||||
 | 
			
		||||
    static constexpr size_t STREAM_BUFFER_SIZE = 4 * 1024 * 1024;
 | 
			
		||||
    std::unique_ptr<OGLStreamBuffer> stream_buffer;
 | 
			
		||||
 | 
			
		||||
    GLint vs_input_index_min;
 | 
			
		||||
    GLint vs_input_index_max;
 | 
			
		||||
    GLsizeiptr vs_input_size;
 | 
			
		||||
 | 
			
		||||
    void AnalyzeVertexArray(bool is_indexed);
 | 
			
		||||
    void SetupVertexArray(u8* array_ptr, GLintptr buffer_offset);
 | 
			
		||||
 | 
			
		||||
    OGLBuffer vs_uniform_buffer;
 | 
			
		||||
    std::unordered_map<GLShader::MaxwellVSConfig, VertexShader*> vs_shader_map;
 | 
			
		||||
    std::unordered_map<std::string, VertexShader> vs_shader_cache;
 | 
			
		||||
    OGLShader vs_default_shader;
 | 
			
		||||
 | 
			
		||||
    void SetupVertexShader(VSUniformData* ub_ptr, GLintptr buffer_offset);
 | 
			
		||||
 | 
			
		||||
    OGLBuffer fs_uniform_buffer;
 | 
			
		||||
    std::unordered_map<GLShader::MaxwellFSConfig, FragmentShader*> fs_shader_map;
 | 
			
		||||
    std::unordered_map<std::string, FragmentShader> fs_shader_cache;
 | 
			
		||||
    OGLShader fs_default_shader;
 | 
			
		||||
 | 
			
		||||
    void SetupFragmentShader(FSUniformData* ub_ptr, GLintptr buffer_offset);
 | 
			
		||||
 | 
			
		||||
    enum class AccelDraw { Disabled, Arrays, Indexed };
 | 
			
		||||
    AccelDraw accelerate_draw;
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										1361
									
								
								src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1361
									
								
								src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										350
									
								
								src/video_core/renderer_opengl/gl_rasterizer_cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								src/video_core/renderer_opengl/gl_rasterizer_cache.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,350 @@
 | 
			
		||||
// Copyright 2015 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <set>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
 | 
			
		||||
#endif
 | 
			
		||||
#include <boost/icl/interval_map.hpp>
 | 
			
		||||
#include <boost/icl/interval_set.hpp>
 | 
			
		||||
#ifdef __GNUC__
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "common/math_util.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
 | 
			
		||||
struct CachedSurface;
 | 
			
		||||
using Surface = std::shared_ptr<CachedSurface>;
 | 
			
		||||
using SurfaceSet = std::set<Surface>;
 | 
			
		||||
 | 
			
		||||
using SurfaceRegions = boost::icl::interval_set<PAddr>;
 | 
			
		||||
using SurfaceMap = boost::icl::interval_map<PAddr, Surface>;
 | 
			
		||||
using SurfaceCache = boost::icl::interval_map<PAddr, SurfaceSet>;
 | 
			
		||||
 | 
			
		||||
using SurfaceInterval = SurfaceCache::interval_type;
 | 
			
		||||
static_assert(std::is_same<SurfaceRegions::interval_type, SurfaceCache::interval_type>() &&
 | 
			
		||||
                  std::is_same<SurfaceMap::interval_type, SurfaceCache::interval_type>(),
 | 
			
		||||
              "incorrect interval types");
 | 
			
		||||
 | 
			
		||||
using SurfaceRect_Tuple = std::tuple<Surface, MathUtil::Rectangle<u32>>;
 | 
			
		||||
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
 | 
			
		||||
 | 
			
		||||
using PageMap = boost::icl::interval_map<u32, int>;
 | 
			
		||||
 | 
			
		||||
enum class ScaleMatch {
 | 
			
		||||
    Exact,   // only accept same res scale
 | 
			
		||||
    Upscale, // only allow higher scale than params
 | 
			
		||||
    Ignore   // accept every scaled res
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SurfaceParams {
 | 
			
		||||
    enum class PixelFormat {
 | 
			
		||||
        // First 5 formats are shared between textures and color buffers
 | 
			
		||||
        RGBA8 = 0,
 | 
			
		||||
        RGB8 = 1,
 | 
			
		||||
        RGB5A1 = 2,
 | 
			
		||||
        RGB565 = 3,
 | 
			
		||||
        RGBA4 = 4,
 | 
			
		||||
 | 
			
		||||
        // Texture-only formats
 | 
			
		||||
        IA8 = 5,
 | 
			
		||||
        RG8 = 6,
 | 
			
		||||
        I8 = 7,
 | 
			
		||||
        A8 = 8,
 | 
			
		||||
        IA4 = 9,
 | 
			
		||||
        I4 = 10,
 | 
			
		||||
        A4 = 11,
 | 
			
		||||
        ETC1 = 12,
 | 
			
		||||
        ETC1A4 = 13,
 | 
			
		||||
 | 
			
		||||
        // Depth buffer-only formats
 | 
			
		||||
        D16 = 14,
 | 
			
		||||
        // gap
 | 
			
		||||
        D24 = 16,
 | 
			
		||||
        D24S8 = 17,
 | 
			
		||||
 | 
			
		||||
        Invalid = 255,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class SurfaceType {
 | 
			
		||||
        Color = 0,
 | 
			
		||||
        Texture = 1,
 | 
			
		||||
        Depth = 2,
 | 
			
		||||
        DepthStencil = 3,
 | 
			
		||||
        Fill = 4,
 | 
			
		||||
        Invalid = 5
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static constexpr unsigned int GetFormatBpp(PixelFormat format) {
 | 
			
		||||
        constexpr std::array<unsigned int, 18> bpp_table = {
 | 
			
		||||
            32, // RGBA8
 | 
			
		||||
            24, // RGB8
 | 
			
		||||
            16, // RGB5A1
 | 
			
		||||
            16, // RGB565
 | 
			
		||||
            16, // RGBA4
 | 
			
		||||
            16, // IA8
 | 
			
		||||
            16, // RG8
 | 
			
		||||
            8,  // I8
 | 
			
		||||
            8,  // A8
 | 
			
		||||
            8,  // IA4
 | 
			
		||||
            4,  // I4
 | 
			
		||||
            4,  // A4
 | 
			
		||||
            4,  // ETC1
 | 
			
		||||
            8,  // ETC1A4
 | 
			
		||||
            16, // D16
 | 
			
		||||
            0,
 | 
			
		||||
            24, // D24
 | 
			
		||||
            32, // D24S8
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assert(static_cast<size_t>(format) < bpp_table.size());
 | 
			
		||||
        return bpp_table[static_cast<size_t>(format)];
 | 
			
		||||
    }
 | 
			
		||||
    unsigned int GetFormatBpp() const {
 | 
			
		||||
        return GetFormatBpp(pixel_format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool CheckFormatsBlittable(PixelFormat pixel_format_a, PixelFormat pixel_format_b) {
 | 
			
		||||
        SurfaceType a_type = GetFormatType(pixel_format_a);
 | 
			
		||||
        SurfaceType b_type = GetFormatType(pixel_format_b);
 | 
			
		||||
 | 
			
		||||
        if ((a_type == SurfaceType::Color || a_type == SurfaceType::Texture) &&
 | 
			
		||||
            (b_type == SurfaceType::Color || b_type == SurfaceType::Texture)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (a_type == SurfaceType::Depth && b_type == SurfaceType::Depth) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (a_type == SurfaceType::DepthStencil && b_type == SurfaceType::DepthStencil) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static constexpr SurfaceType GetFormatType(PixelFormat pixel_format) {
 | 
			
		||||
        if ((unsigned int)pixel_format < 5) {
 | 
			
		||||
            return SurfaceType::Color;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((unsigned int)pixel_format < 14) {
 | 
			
		||||
            return SurfaceType::Texture;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pixel_format == PixelFormat::D16 || pixel_format == PixelFormat::D24) {
 | 
			
		||||
            return SurfaceType::Depth;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (pixel_format == PixelFormat::D24S8) {
 | 
			
		||||
            return SurfaceType::DepthStencil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return SurfaceType::Invalid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Update the params "size", "end" and "type" from the already set "addr", "width", "height"
 | 
			
		||||
    /// and "pixel_format"
 | 
			
		||||
    void UpdateParams() {
 | 
			
		||||
        if (stride == 0) {
 | 
			
		||||
            stride = width;
 | 
			
		||||
        }
 | 
			
		||||
        type = GetFormatType(pixel_format);
 | 
			
		||||
        size = !is_tiled ? BytesInPixels(stride * (height - 1) + width)
 | 
			
		||||
                         : BytesInPixels(stride * 8 * (height / 8 - 1) + width * 8);
 | 
			
		||||
        end = addr + size;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SurfaceInterval GetInterval() const {
 | 
			
		||||
        return SurfaceInterval::right_open(addr, end);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Returns the outer rectangle containing "interval"
 | 
			
		||||
    SurfaceParams FromInterval(SurfaceInterval interval) const;
 | 
			
		||||
 | 
			
		||||
    SurfaceInterval GetSubRectInterval(MathUtil::Rectangle<u32> unscaled_rect) const;
 | 
			
		||||
 | 
			
		||||
    // Returns the region of the biggest valid rectange within interval
 | 
			
		||||
    SurfaceInterval GetCopyableInterval(const Surface& src_surface) const;
 | 
			
		||||
 | 
			
		||||
    u32 GetScaledWidth() const {
 | 
			
		||||
        return width * res_scale;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u32 GetScaledHeight() const {
 | 
			
		||||
        return height * res_scale;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MathUtil::Rectangle<u32> GetRect() const {
 | 
			
		||||
        return {0, height, width, 0};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MathUtil::Rectangle<u32> GetScaledRect() const {
 | 
			
		||||
        return {0, GetScaledHeight(), GetScaledWidth(), 0};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u64 PixelsInBytes(u64 size) const {
 | 
			
		||||
        return size * CHAR_BIT / GetFormatBpp(pixel_format);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    u64 BytesInPixels(u64 pixels) const {
 | 
			
		||||
        return pixels * GetFormatBpp(pixel_format) / CHAR_BIT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool ExactMatch(const SurfaceParams& other_surface) const;
 | 
			
		||||
    bool CanSubRect(const SurfaceParams& sub_surface) const;
 | 
			
		||||
    bool CanExpand(const SurfaceParams& expanded_surface) const;
 | 
			
		||||
    bool CanTexCopy(const SurfaceParams& texcopy_params) const;
 | 
			
		||||
 | 
			
		||||
    MathUtil::Rectangle<u32> GetSubRect(const SurfaceParams& sub_surface) const;
 | 
			
		||||
    MathUtil::Rectangle<u32> GetScaledSubRect(const SurfaceParams& sub_surface) const;
 | 
			
		||||
 | 
			
		||||
    PAddr addr = 0;
 | 
			
		||||
    PAddr end = 0;
 | 
			
		||||
    u64 size = 0;
 | 
			
		||||
 | 
			
		||||
    u32 width = 0;
 | 
			
		||||
    u32 height = 0;
 | 
			
		||||
    u32 stride = 0;
 | 
			
		||||
    u16 res_scale = 1;
 | 
			
		||||
 | 
			
		||||
    bool is_tiled = false;
 | 
			
		||||
    PixelFormat pixel_format = PixelFormat::Invalid;
 | 
			
		||||
    SurfaceType type = SurfaceType::Invalid;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct CachedSurface : SurfaceParams {
 | 
			
		||||
    bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
 | 
			
		||||
    bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
 | 
			
		||||
 | 
			
		||||
    bool IsRegionValid(SurfaceInterval interval) const {
 | 
			
		||||
        return (invalid_regions.find(interval) == invalid_regions.end());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsSurfaceFullyInvalid() const {
 | 
			
		||||
        return (invalid_regions & GetInterval()) == SurfaceRegions(GetInterval());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool registered = false;
 | 
			
		||||
    SurfaceRegions invalid_regions;
 | 
			
		||||
 | 
			
		||||
    u64 fill_size = 0; /// Number of bytes to read from fill_data
 | 
			
		||||
    std::array<u8, 4> fill_data;
 | 
			
		||||
 | 
			
		||||
    OGLTexture texture;
 | 
			
		||||
 | 
			
		||||
    static constexpr unsigned int GetGLBytesPerPixel(PixelFormat format) {
 | 
			
		||||
        // OpenGL needs 4 bpp alignment for D24 since using GL_UNSIGNED_INT as type
 | 
			
		||||
        return format == PixelFormat::Invalid
 | 
			
		||||
                   ? 0
 | 
			
		||||
                   : (format == PixelFormat::D24 || GetFormatType(format) == SurfaceType::Texture)
 | 
			
		||||
                         ? 4
 | 
			
		||||
                         : SurfaceParams::GetFormatBpp(format) / 8;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<u8[]> gl_buffer;
 | 
			
		||||
    size_t gl_buffer_size = 0;
 | 
			
		||||
 | 
			
		||||
    // Read/Write data in 3DS memory to/from gl_buffer
 | 
			
		||||
    void LoadGLBuffer(PAddr load_start, PAddr load_end);
 | 
			
		||||
    void FlushGLBuffer(PAddr flush_start, PAddr flush_end);
 | 
			
		||||
 | 
			
		||||
    // Upload/Download data in gl_buffer in/to this surface's texture
 | 
			
		||||
    void UploadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
 | 
			
		||||
                         GLuint draw_fb_handle);
 | 
			
		||||
    void DownloadGLTexture(const MathUtil::Rectangle<u32>& rect, GLuint read_fb_handle,
 | 
			
		||||
                           GLuint draw_fb_handle);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class RasterizerCacheOpenGL : NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    RasterizerCacheOpenGL();
 | 
			
		||||
    ~RasterizerCacheOpenGL();
 | 
			
		||||
 | 
			
		||||
    /// Blit one surface's texture to another
 | 
			
		||||
    bool BlitSurfaces(const Surface& src_surface, const MathUtil::Rectangle<u32>& src_rect,
 | 
			
		||||
                      const Surface& dst_surface, const MathUtil::Rectangle<u32>& dst_rect);
 | 
			
		||||
 | 
			
		||||
    void ConvertD24S8toABGR(GLuint src_tex, const MathUtil::Rectangle<u32>& src_rect,
 | 
			
		||||
                            GLuint dst_tex, const MathUtil::Rectangle<u32>& dst_rect);
 | 
			
		||||
 | 
			
		||||
    /// Copy one surface's region to another
 | 
			
		||||
    void CopySurface(const Surface& src_surface, const Surface& dst_surface,
 | 
			
		||||
                     SurfaceInterval copy_interval);
 | 
			
		||||
 | 
			
		||||
    /// Load a texture from 3DS memory to OpenGL and cache it (if not already cached)
 | 
			
		||||
    Surface GetSurface(const SurfaceParams& params, ScaleMatch match_res_scale,
 | 
			
		||||
                       bool load_if_create);
 | 
			
		||||
 | 
			
		||||
    /// Attempt to find a subrect (resolution scaled) of a surface, otherwise loads a texture from
 | 
			
		||||
    /// 3DS memory to OpenGL and caches it (if not already cached)
 | 
			
		||||
    SurfaceRect_Tuple GetSurfaceSubRect(const SurfaceParams& params, ScaleMatch match_res_scale,
 | 
			
		||||
                                        bool load_if_create);
 | 
			
		||||
 | 
			
		||||
    /// Get a surface based on the texture configuration
 | 
			
		||||
    Surface GetTextureSurface(const void* config);
 | 
			
		||||
 | 
			
		||||
    /// Get the color and depth surfaces based on the framebuffer configuration
 | 
			
		||||
    SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb,
 | 
			
		||||
                                                    const MathUtil::Rectangle<s32>& viewport_rect);
 | 
			
		||||
 | 
			
		||||
    /// Get a surface that matches the fill config
 | 
			
		||||
    Surface GetFillSurface(const void* config);
 | 
			
		||||
 | 
			
		||||
    /// Get a surface that matches a "texture copy" display transfer config
 | 
			
		||||
    SurfaceRect_Tuple GetTexCopySurface(const SurfaceParams& params);
 | 
			
		||||
 | 
			
		||||
    /// Write any cached resources overlapping the region back to memory (if dirty)
 | 
			
		||||
    void FlushRegion(PAddr addr, u64 size, Surface flush_surface = nullptr);
 | 
			
		||||
 | 
			
		||||
    /// Mark region as being invalidated by region_owner (nullptr if 3DS memory)
 | 
			
		||||
    void InvalidateRegion(PAddr addr, u64 size, const Surface& region_owner);
 | 
			
		||||
 | 
			
		||||
    /// Flush all cached resources tracked by this cache manager
 | 
			
		||||
    void FlushAll();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void DuplicateSurface(const Surface& src_surface, const Surface& dest_surface);
 | 
			
		||||
 | 
			
		||||
    /// Update surface's texture for given region when necessary
 | 
			
		||||
    void ValidateSurface(const Surface& surface, PAddr addr, u64 size);
 | 
			
		||||
 | 
			
		||||
    /// Create a new surface
 | 
			
		||||
    Surface CreateSurface(const SurfaceParams& params);
 | 
			
		||||
 | 
			
		||||
    /// Register surface into the cache
 | 
			
		||||
    void RegisterSurface(const Surface& surface);
 | 
			
		||||
 | 
			
		||||
    /// Remove surface from the cache
 | 
			
		||||
    void UnregisterSurface(const Surface& surface);
 | 
			
		||||
 | 
			
		||||
    /// Increase/decrease the number of surface in pages touching the specified region
 | 
			
		||||
    void UpdatePagesCachedCount(PAddr addr, u64 size, int delta);
 | 
			
		||||
 | 
			
		||||
    SurfaceCache surface_cache;
 | 
			
		||||
    PageMap cached_pages;
 | 
			
		||||
    SurfaceMap dirty_regions;
 | 
			
		||||
    SurfaceSet remove_surfaces;
 | 
			
		||||
 | 
			
		||||
    OGLFramebuffer read_framebuffer;
 | 
			
		||||
    OGLFramebuffer draw_framebuffer;
 | 
			
		||||
 | 
			
		||||
    OGLVertexArray attributeless_vao;
 | 
			
		||||
    OGLBuffer d24s8_abgr_buffer;
 | 
			
		||||
    GLsizeiptr d24s8_abgr_buffer_size;
 | 
			
		||||
    OGLShader d24s8_abgr_shader;
 | 
			
		||||
    GLint d24s8_abgr_tbo_size_u_id;
 | 
			
		||||
    GLint d24s8_abgr_viewport_u_id;
 | 
			
		||||
};
 | 
			
		||||
@ -36,7 +36,7 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteTextures(1, &handle);
 | 
			
		||||
        OpenGLState::ResetTexture(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetTexture(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -69,7 +69,7 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteSamplers(1, &handle);
 | 
			
		||||
        OpenGLState::ResetSampler(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetSampler(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -91,10 +91,13 @@ public:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a new internal OpenGL resource and stores the handle
 | 
			
		||||
    void Create(const char* vert_shader, const char* frag_shader) {
 | 
			
		||||
    void Create(const char* vert_shader, const char* geo_shader, const char* frag_shader,
 | 
			
		||||
                const std::vector<const char*>& feedback_vars = {},
 | 
			
		||||
                bool separable_program = false) {
 | 
			
		||||
        if (handle != 0)
 | 
			
		||||
            return;
 | 
			
		||||
        handle = GLShader::LoadProgram(vert_shader, frag_shader);
 | 
			
		||||
        handle = GLShader::LoadProgram(vert_shader, geo_shader, frag_shader, feedback_vars,
 | 
			
		||||
                                       separable_program);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Deletes the internal OpenGL resource
 | 
			
		||||
@ -102,7 +105,40 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteProgram(handle);
 | 
			
		||||
        OpenGLState::ResetProgram(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetProgram(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLuint handle = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OGLPipeline : private NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    OGLPipeline() = default;
 | 
			
		||||
    OGLPipeline(OGLPipeline&& o) {
 | 
			
		||||
        handle = std::exchange<GLuint>(o.handle, 0);
 | 
			
		||||
    }
 | 
			
		||||
    ~OGLPipeline() {
 | 
			
		||||
        Release();
 | 
			
		||||
    }
 | 
			
		||||
    OGLPipeline& operator=(OGLPipeline&& o) {
 | 
			
		||||
        handle = std::exchange<GLuint>(o.handle, 0);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a new internal OpenGL resource and stores the handle
 | 
			
		||||
    void Create() {
 | 
			
		||||
        if (handle != 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glGenProgramPipelines(1, &handle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Deletes the internal OpenGL resource
 | 
			
		||||
    void Release() {
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteProgramPipelines(1, &handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetPipeline(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -135,13 +171,46 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteBuffers(1, &handle);
 | 
			
		||||
        OpenGLState::ResetBuffer(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetBuffer(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLuint handle = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OGLSync : private NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    OGLSync() = default;
 | 
			
		||||
 | 
			
		||||
    OGLSync(OGLSync&& o) : handle(std::exchange(o.handle, nullptr)) {}
 | 
			
		||||
 | 
			
		||||
    ~OGLSync() {
 | 
			
		||||
        Release();
 | 
			
		||||
    }
 | 
			
		||||
    OGLSync& operator=(OGLSync&& o) {
 | 
			
		||||
        Release();
 | 
			
		||||
        handle = std::exchange(o.handle, nullptr);
 | 
			
		||||
        return *this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Creates a new internal OpenGL resource and stores the handle
 | 
			
		||||
    void Create() {
 | 
			
		||||
        if (handle != 0)
 | 
			
		||||
            return;
 | 
			
		||||
        handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Deletes the internal OpenGL resource
 | 
			
		||||
    void Release() {
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteSync(handle);
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GLsync handle = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class OGLVertexArray : private NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    OGLVertexArray() = default;
 | 
			
		||||
@ -168,7 +237,7 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteVertexArrays(1, &handle);
 | 
			
		||||
        OpenGLState::ResetVertexArray(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -201,7 +270,7 @@ public:
 | 
			
		||||
        if (handle == 0)
 | 
			
		||||
            return;
 | 
			
		||||
        glDeleteFramebuffers(1, &handle);
 | 
			
		||||
        OpenGLState::ResetFramebuffer(handle);
 | 
			
		||||
        OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
 | 
			
		||||
        handle = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								src/video_core/renderer_opengl/gl_shader_decompiler.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/video_core/renderer_opengl/gl_shader_decompiler.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
// Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <queue>
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
 | 
			
		||||
 | 
			
		||||
namespace Maxwell3D {
 | 
			
		||||
namespace Shader {
 | 
			
		||||
namespace Decompiler {
 | 
			
		||||
 | 
			
		||||
constexpr u32 PROGRAM_END = MAX_PROGRAM_CODE_LENGTH;
 | 
			
		||||
 | 
			
		||||
class Impl {
 | 
			
		||||
public:
 | 
			
		||||
    Impl(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
 | 
			
		||||
         const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data, u32 main_offset,
 | 
			
		||||
         const std::function<std::string(u32)>& inputreg_getter,
 | 
			
		||||
         const std::function<std::string(u32)>& outputreg_getter, bool sanitize_mul,
 | 
			
		||||
         const std::string& emit_cb, const std::string& setemit_cb)
 | 
			
		||||
        : program_code(program_code), swizzle_data(swizzle_data), main_offset(main_offset),
 | 
			
		||||
          inputreg_getter(inputreg_getter), outputreg_getter(outputreg_getter),
 | 
			
		||||
          sanitize_mul(sanitize_mul), emit_cb(emit_cb), setemit_cb(setemit_cb) {}
 | 
			
		||||
 | 
			
		||||
    std::string Decompile() {
 | 
			
		||||
        UNIMPLEMENTED();
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code;
 | 
			
		||||
    const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data;
 | 
			
		||||
    u32 main_offset;
 | 
			
		||||
    const std::function<std::string(u32)>& inputreg_getter;
 | 
			
		||||
    const std::function<std::string(u32)>& outputreg_getter;
 | 
			
		||||
    bool sanitize_mul;
 | 
			
		||||
    const std::string& emit_cb;
 | 
			
		||||
    const std::string& setemit_cb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
 | 
			
		||||
                             const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data,
 | 
			
		||||
                             u32 main_offset,
 | 
			
		||||
                             const std::function<std::string(u32)>& inputreg_getter,
 | 
			
		||||
                             const std::function<std::string(u32)>& outputreg_getter,
 | 
			
		||||
                             bool sanitize_mul, const std::string& emit_cb,
 | 
			
		||||
                             const std::string& setemit_cb) {
 | 
			
		||||
    Impl impl(program_code, swizzle_data, main_offset, inputreg_getter, outputreg_getter,
 | 
			
		||||
              sanitize_mul, emit_cb, setemit_cb);
 | 
			
		||||
    return impl.Decompile();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Decompiler
 | 
			
		||||
} // namespace Shader
 | 
			
		||||
} // namespace Maxwell3D
 | 
			
		||||
							
								
								
									
										27
									
								
								src/video_core/renderer_opengl/gl_shader_decompiler.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/video_core/renderer_opengl/gl_shader_decompiler.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
// Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
namespace Maxwell3D {
 | 
			
		||||
namespace Shader {
 | 
			
		||||
namespace Decompiler {
 | 
			
		||||
 | 
			
		||||
constexpr size_t MAX_PROGRAM_CODE_LENGTH{0x100000};
 | 
			
		||||
constexpr size_t MAX_SWIZZLE_DATA_LENGTH{0x100000};
 | 
			
		||||
 | 
			
		||||
std::string DecompileProgram(const std::array<u32, MAX_PROGRAM_CODE_LENGTH>& program_code,
 | 
			
		||||
                             const std::array<u32, MAX_SWIZZLE_DATA_LENGTH>& swizzle_data,
 | 
			
		||||
                             u32 main_offset,
 | 
			
		||||
                             const std::function<std::string(u32)>& inputreg_getter,
 | 
			
		||||
                             const std::function<std::string(u32)>& outputreg_getter,
 | 
			
		||||
                             bool sanitize_mul, const std::string& emit_cb = "",
 | 
			
		||||
                             const std::string& setemit_cb = "");
 | 
			
		||||
 | 
			
		||||
} // namespace Decompiler
 | 
			
		||||
} // namespace Shader
 | 
			
		||||
} // namespace Maxwell3D
 | 
			
		||||
							
								
								
									
										20
									
								
								src/video_core/renderer_opengl/gl_shader_gen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/video_core/renderer_opengl/gl_shader_gen.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
			
		||||
// Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
 | 
			
		||||
std::string GenerateVertexShader(const MaxwellVSConfig& config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::string GenerateFragmentShader(const MaxwellFSConfig& config) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    return {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace GLShader
 | 
			
		||||
							
								
								
									
										66
									
								
								src/video_core/renderer_opengl/gl_shader_gen.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/video_core/renderer_opengl/gl_shader_gen.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
// Copyright 2018 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <cstring>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <type_traits>
 | 
			
		||||
#include "common/hash.h"
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
 | 
			
		||||
enum Attributes {
 | 
			
		||||
    ATTRIBUTE_POSITION,
 | 
			
		||||
    ATTRIBUTE_COLOR,
 | 
			
		||||
    ATTRIBUTE_TEXCOORD0,
 | 
			
		||||
    ATTRIBUTE_TEXCOORD1,
 | 
			
		||||
    ATTRIBUTE_TEXCOORD2,
 | 
			
		||||
    ATTRIBUTE_TEXCOORD0_W,
 | 
			
		||||
    ATTRIBUTE_NORMQUAT,
 | 
			
		||||
    ATTRIBUTE_VIEW,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MaxwellShaderConfigCommon {
 | 
			
		||||
    explicit MaxwellShaderConfigCommon(){};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MaxwellVSConfig : MaxwellShaderConfigCommon {
 | 
			
		||||
    explicit MaxwellVSConfig() : MaxwellShaderConfigCommon() {}
 | 
			
		||||
 | 
			
		||||
    bool operator==(const MaxwellVSConfig& o) const {
 | 
			
		||||
        return std::memcmp(this, &o, sizeof(MaxwellVSConfig)) == 0;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MaxwellFSConfig : MaxwellShaderConfigCommon {
 | 
			
		||||
    explicit MaxwellFSConfig() : MaxwellShaderConfigCommon() {}
 | 
			
		||||
 | 
			
		||||
    bool operator==(const MaxwellFSConfig& o) const {
 | 
			
		||||
        return std::memcmp(this, &o, sizeof(MaxwellFSConfig)) == 0;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::string GenerateVertexShader(const MaxwellVSConfig& config);
 | 
			
		||||
std::string GenerateFragmentShader(const MaxwellFSConfig& config);
 | 
			
		||||
 | 
			
		||||
} // namespace GLShader
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<GLShader::MaxwellVSConfig> {
 | 
			
		||||
    size_t operator()(const GLShader::MaxwellVSConfig& k) const {
 | 
			
		||||
        return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellVSConfig));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<GLShader::MaxwellFSConfig> {
 | 
			
		||||
    size_t operator()(const GLShader::MaxwellFSConfig& k) const {
 | 
			
		||||
        return Common::ComputeHash64(&k, sizeof(GLShader::MaxwellFSConfig));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace std
 | 
			
		||||
@ -10,53 +10,85 @@
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
 | 
			
		||||
GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
 | 
			
		||||
 | 
			
		||||
GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
 | 
			
		||||
                   const char* fragment_shader, const std::vector<const char*>& feedback_vars,
 | 
			
		||||
                   bool separable_program) {
 | 
			
		||||
    // Create the shaders
 | 
			
		||||
    GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
 | 
			
		||||
    GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER);
 | 
			
		||||
    GLuint vertex_shader_id = vertex_shader ? glCreateShader(GL_VERTEX_SHADER) : 0;
 | 
			
		||||
    GLuint geometry_shader_id = geometry_shader ? glCreateShader(GL_GEOMETRY_SHADER) : 0;
 | 
			
		||||
    GLuint fragment_shader_id = fragment_shader ? glCreateShader(GL_FRAGMENT_SHADER) : 0;
 | 
			
		||||
 | 
			
		||||
    GLint result = GL_FALSE;
 | 
			
		||||
    int info_log_length;
 | 
			
		||||
 | 
			
		||||
    // Compile Vertex Shader
 | 
			
		||||
    LOG_DEBUG(Render_OpenGL, "Compiling vertex shader...");
 | 
			
		||||
    if (vertex_shader) {
 | 
			
		||||
        // Compile Vertex Shader
 | 
			
		||||
        LOG_DEBUG(Render_OpenGL, "Compiling vertex shader...");
 | 
			
		||||
 | 
			
		||||
    glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr);
 | 
			
		||||
    glCompileShader(vertex_shader_id);
 | 
			
		||||
        glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr);
 | 
			
		||||
        glCompileShader(vertex_shader_id);
 | 
			
		||||
 | 
			
		||||
    // Check Vertex Shader
 | 
			
		||||
    glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
 | 
			
		||||
    glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 | 
			
		||||
        // Check Vertex Shader
 | 
			
		||||
        glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
 | 
			
		||||
        glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 | 
			
		||||
 | 
			
		||||
    if (info_log_length > 1) {
 | 
			
		||||
        std::vector<char> vertex_shader_error(info_log_length);
 | 
			
		||||
        glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
 | 
			
		||||
        if (result == GL_TRUE) {
 | 
			
		||||
            LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", &vertex_shader_error[0]);
 | 
			
		||||
        if (info_log_length > 1) {
 | 
			
		||||
            std::vector<char> vertex_shader_error(info_log_length);
 | 
			
		||||
            glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
 | 
			
		||||
            if (result == GL_TRUE) {
 | 
			
		||||
                LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s",
 | 
			
		||||
                          &vertex_shader_error[0]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Compile Fragment Shader
 | 
			
		||||
    LOG_DEBUG(Render_OpenGL, "Compiling fragment shader...");
 | 
			
		||||
    if (geometry_shader) {
 | 
			
		||||
        // Compile Geometry Shader
 | 
			
		||||
        LOG_DEBUG(Render_OpenGL, "Compiling geometry shader...");
 | 
			
		||||
 | 
			
		||||
    glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr);
 | 
			
		||||
    glCompileShader(fragment_shader_id);
 | 
			
		||||
        glShaderSource(geometry_shader_id, 1, &geometry_shader, nullptr);
 | 
			
		||||
        glCompileShader(geometry_shader_id);
 | 
			
		||||
 | 
			
		||||
    // Check Fragment Shader
 | 
			
		||||
    glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
 | 
			
		||||
    glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 | 
			
		||||
        // Check Geometry Shader
 | 
			
		||||
        glGetShaderiv(geometry_shader_id, GL_COMPILE_STATUS, &result);
 | 
			
		||||
        glGetShaderiv(geometry_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 | 
			
		||||
 | 
			
		||||
    if (info_log_length > 1) {
 | 
			
		||||
        std::vector<char> fragment_shader_error(info_log_length);
 | 
			
		||||
        glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, &fragment_shader_error[0]);
 | 
			
		||||
        if (result == GL_TRUE) {
 | 
			
		||||
            LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
 | 
			
		||||
        } else {
 | 
			
		||||
            LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s",
 | 
			
		||||
                      &fragment_shader_error[0]);
 | 
			
		||||
        if (info_log_length > 1) {
 | 
			
		||||
            std::vector<char> geometry_shader_error(info_log_length);
 | 
			
		||||
            glGetShaderInfoLog(geometry_shader_id, info_log_length, nullptr,
 | 
			
		||||
                               &geometry_shader_error[0]);
 | 
			
		||||
            if (result == GL_TRUE) {
 | 
			
		||||
                LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOG_ERROR(Render_OpenGL, "Error compiling geometry shader:\n%s",
 | 
			
		||||
                          &geometry_shader_error[0]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fragment_shader) {
 | 
			
		||||
        // Compile Fragment Shader
 | 
			
		||||
        LOG_DEBUG(Render_OpenGL, "Compiling fragment shader...");
 | 
			
		||||
 | 
			
		||||
        glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr);
 | 
			
		||||
        glCompileShader(fragment_shader_id);
 | 
			
		||||
 | 
			
		||||
        // Check Fragment Shader
 | 
			
		||||
        glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
 | 
			
		||||
        glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
 | 
			
		||||
 | 
			
		||||
        if (info_log_length > 1) {
 | 
			
		||||
            std::vector<char> fragment_shader_error(info_log_length);
 | 
			
		||||
            glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr,
 | 
			
		||||
                               &fragment_shader_error[0]);
 | 
			
		||||
            if (result == GL_TRUE) {
 | 
			
		||||
                LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
 | 
			
		||||
            } else {
 | 
			
		||||
                LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s",
 | 
			
		||||
                          &fragment_shader_error[0]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -64,8 +96,25 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
 | 
			
		||||
    LOG_DEBUG(Render_OpenGL, "Linking program...");
 | 
			
		||||
 | 
			
		||||
    GLuint program_id = glCreateProgram();
 | 
			
		||||
    glAttachShader(program_id, vertex_shader_id);
 | 
			
		||||
    glAttachShader(program_id, fragment_shader_id);
 | 
			
		||||
    if (vertex_shader) {
 | 
			
		||||
        glAttachShader(program_id, vertex_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
    if (geometry_shader) {
 | 
			
		||||
        glAttachShader(program_id, geometry_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
    if (fragment_shader) {
 | 
			
		||||
        glAttachShader(program_id, fragment_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!feedback_vars.empty()) {
 | 
			
		||||
        auto varyings = feedback_vars;
 | 
			
		||||
        glTransformFeedbackVaryings(program_id, static_cast<GLsizei>(feedback_vars.size()),
 | 
			
		||||
                                    &varyings[0], GL_INTERLEAVED_ATTRIBS);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (separable_program) {
 | 
			
		||||
        glProgramParameteri(program_id, GL_PROGRAM_SEPARABLE, GL_TRUE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glLinkProgram(program_id);
 | 
			
		||||
 | 
			
		||||
@ -85,13 +134,30 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) {
 | 
			
		||||
 | 
			
		||||
    // If the program linking failed at least one of the shaders was probably bad
 | 
			
		||||
    if (result == GL_FALSE) {
 | 
			
		||||
        LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader);
 | 
			
		||||
        LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader);
 | 
			
		||||
        if (vertex_shader) {
 | 
			
		||||
            LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader);
 | 
			
		||||
        }
 | 
			
		||||
        if (geometry_shader) {
 | 
			
		||||
            LOG_ERROR(Render_OpenGL, "Geometry shader:\n%s", geometry_shader);
 | 
			
		||||
        }
 | 
			
		||||
        if (fragment_shader) {
 | 
			
		||||
            LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    ASSERT_MSG(result == GL_TRUE, "Shader not linked");
 | 
			
		||||
 | 
			
		||||
    glDeleteShader(vertex_shader_id);
 | 
			
		||||
    glDeleteShader(fragment_shader_id);
 | 
			
		||||
    if (vertex_shader) {
 | 
			
		||||
        glDetachShader(program_id, vertex_shader_id);
 | 
			
		||||
        glDeleteShader(vertex_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
    if (geometry_shader) {
 | 
			
		||||
        glDetachShader(program_id, geometry_shader_id);
 | 
			
		||||
        glDeleteShader(geometry_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
    if (fragment_shader) {
 | 
			
		||||
        glDetachShader(program_id, fragment_shader_id);
 | 
			
		||||
        glDeleteShader(fragment_shader_id);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return program_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
namespace GLShader {
 | 
			
		||||
@ -11,9 +12,12 @@ namespace GLShader {
 | 
			
		||||
/**
 | 
			
		||||
 * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader)
 | 
			
		||||
 * @param vertex_shader String of the GLSL vertex shader program
 | 
			
		||||
 * @param geometry_shader String of the GLSL geometry shader program
 | 
			
		||||
 * @param fragment_shader String of the GLSL fragment shader program
 | 
			
		||||
 * @returns Handle of the newly created OpenGL shader object
 | 
			
		||||
 */
 | 
			
		||||
GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader);
 | 
			
		||||
GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader,
 | 
			
		||||
                   const char* fragment_shader, const std::vector<const char*>& feedback_vars = {},
 | 
			
		||||
                   bool separable_program = false);
 | 
			
		||||
 | 
			
		||||
} // namespace GLShader
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ OpenGLState::OpenGLState() {
 | 
			
		||||
    stencil.action_depth_pass = GL_KEEP;
 | 
			
		||||
    stencil.action_stencil_fail = GL_KEEP;
 | 
			
		||||
 | 
			
		||||
    blend.enabled = false;
 | 
			
		||||
    blend.enabled = true;
 | 
			
		||||
    blend.rgb_equation = GL_FUNC_ADD;
 | 
			
		||||
    blend.a_equation = GL_FUNC_ADD;
 | 
			
		||||
    blend.src_rgb_func = GL_ONE;
 | 
			
		||||
@ -68,6 +68,18 @@ OpenGLState::OpenGLState() {
 | 
			
		||||
    draw.vertex_buffer = 0;
 | 
			
		||||
    draw.uniform_buffer = 0;
 | 
			
		||||
    draw.shader_program = 0;
 | 
			
		||||
    draw.program_pipeline = 0;
 | 
			
		||||
 | 
			
		||||
    scissor.enabled = false;
 | 
			
		||||
    scissor.x = 0;
 | 
			
		||||
    scissor.y = 0;
 | 
			
		||||
    scissor.width = 0;
 | 
			
		||||
    scissor.height = 0;
 | 
			
		||||
 | 
			
		||||
    viewport.x = 0;
 | 
			
		||||
    viewport.y = 0;
 | 
			
		||||
    viewport.width = 0;
 | 
			
		||||
    viewport.height = 0;
 | 
			
		||||
 | 
			
		||||
    clip_distance = {};
 | 
			
		||||
}
 | 
			
		||||
@ -148,9 +160,6 @@ void OpenGLState::Apply() const {
 | 
			
		||||
    if (blend.enabled != cur_state.blend.enabled) {
 | 
			
		||||
        if (blend.enabled) {
 | 
			
		||||
            glEnable(GL_BLEND);
 | 
			
		||||
 | 
			
		||||
            cur_state.logic_op = GL_COPY;
 | 
			
		||||
            glLogicOp(cur_state.logic_op);
 | 
			
		||||
            glDisable(GL_COLOR_LOGIC_OP);
 | 
			
		||||
        } else {
 | 
			
		||||
            glDisable(GL_BLEND);
 | 
			
		||||
@ -196,7 +205,7 @@ void OpenGLState::Apply() const {
 | 
			
		||||
    // Lighting LUTs
 | 
			
		||||
    if (lighting_lut.texture_buffer != cur_state.lighting_lut.texture_buffer) {
 | 
			
		||||
        glActiveTexture(TextureUnits::LightingLUT.Enum());
 | 
			
		||||
        glBindTexture(GL_TEXTURE_BUFFER, cur_state.lighting_lut.texture_buffer);
 | 
			
		||||
        glBindTexture(GL_TEXTURE_BUFFER, lighting_lut.texture_buffer);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Fog LUT
 | 
			
		||||
@ -263,6 +272,31 @@ void OpenGLState::Apply() const {
 | 
			
		||||
        glUseProgram(draw.shader_program);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Program pipeline
 | 
			
		||||
    if (draw.program_pipeline != cur_state.draw.program_pipeline) {
 | 
			
		||||
        glBindProgramPipeline(draw.program_pipeline);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Scissor test
 | 
			
		||||
    if (scissor.enabled != cur_state.scissor.enabled) {
 | 
			
		||||
        if (scissor.enabled) {
 | 
			
		||||
            glEnable(GL_SCISSOR_TEST);
 | 
			
		||||
        } else {
 | 
			
		||||
            glDisable(GL_SCISSOR_TEST);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
 | 
			
		||||
        scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) {
 | 
			
		||||
        glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
 | 
			
		||||
        viewport.width != cur_state.viewport.width ||
 | 
			
		||||
        viewport.height != cur_state.viewport.height) {
 | 
			
		||||
        glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Clip distance
 | 
			
		||||
    for (size_t i = 0; i < clip_distance.size(); ++i) {
 | 
			
		||||
        if (clip_distance[i] != cur_state.clip_distance[i]) {
 | 
			
		||||
@ -277,62 +311,75 @@ void OpenGLState::Apply() const {
 | 
			
		||||
    cur_state = *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetTexture(GLuint handle) {
 | 
			
		||||
    for (auto& unit : cur_state.texture_units) {
 | 
			
		||||
OpenGLState& OpenGLState::ResetTexture(GLuint handle) {
 | 
			
		||||
    for (auto& unit : texture_units) {
 | 
			
		||||
        if (unit.texture_2d == handle) {
 | 
			
		||||
            unit.texture_2d = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (cur_state.lighting_lut.texture_buffer == handle)
 | 
			
		||||
        cur_state.lighting_lut.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.fog_lut.texture_buffer == handle)
 | 
			
		||||
        cur_state.fog_lut.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.proctex_noise_lut.texture_buffer == handle)
 | 
			
		||||
        cur_state.proctex_noise_lut.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.proctex_color_map.texture_buffer == handle)
 | 
			
		||||
        cur_state.proctex_color_map.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.proctex_alpha_map.texture_buffer == handle)
 | 
			
		||||
        cur_state.proctex_alpha_map.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.proctex_lut.texture_buffer == handle)
 | 
			
		||||
        cur_state.proctex_lut.texture_buffer = 0;
 | 
			
		||||
    if (cur_state.proctex_diff_lut.texture_buffer == handle)
 | 
			
		||||
        cur_state.proctex_diff_lut.texture_buffer = 0;
 | 
			
		||||
    if (lighting_lut.texture_buffer == handle)
 | 
			
		||||
        lighting_lut.texture_buffer = 0;
 | 
			
		||||
    if (fog_lut.texture_buffer == handle)
 | 
			
		||||
        fog_lut.texture_buffer = 0;
 | 
			
		||||
    if (proctex_noise_lut.texture_buffer == handle)
 | 
			
		||||
        proctex_noise_lut.texture_buffer = 0;
 | 
			
		||||
    if (proctex_color_map.texture_buffer == handle)
 | 
			
		||||
        proctex_color_map.texture_buffer = 0;
 | 
			
		||||
    if (proctex_alpha_map.texture_buffer == handle)
 | 
			
		||||
        proctex_alpha_map.texture_buffer = 0;
 | 
			
		||||
    if (proctex_lut.texture_buffer == handle)
 | 
			
		||||
        proctex_lut.texture_buffer = 0;
 | 
			
		||||
    if (proctex_diff_lut.texture_buffer == handle)
 | 
			
		||||
        proctex_diff_lut.texture_buffer = 0;
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetSampler(GLuint handle) {
 | 
			
		||||
    for (auto& unit : cur_state.texture_units) {
 | 
			
		||||
OpenGLState& OpenGLState::ResetSampler(GLuint handle) {
 | 
			
		||||
    for (auto& unit : texture_units) {
 | 
			
		||||
        if (unit.sampler == handle) {
 | 
			
		||||
            unit.sampler = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetProgram(GLuint handle) {
 | 
			
		||||
    if (cur_state.draw.shader_program == handle) {
 | 
			
		||||
        cur_state.draw.shader_program = 0;
 | 
			
		||||
OpenGLState& OpenGLState::ResetProgram(GLuint handle) {
 | 
			
		||||
    if (draw.shader_program == handle) {
 | 
			
		||||
        draw.shader_program = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetBuffer(GLuint handle) {
 | 
			
		||||
    if (cur_state.draw.vertex_buffer == handle) {
 | 
			
		||||
        cur_state.draw.vertex_buffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (cur_state.draw.uniform_buffer == handle) {
 | 
			
		||||
        cur_state.draw.uniform_buffer = 0;
 | 
			
		||||
OpenGLState& OpenGLState::ResetPipeline(GLuint handle) {
 | 
			
		||||
    if (draw.program_pipeline == handle) {
 | 
			
		||||
        draw.program_pipeline = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetVertexArray(GLuint handle) {
 | 
			
		||||
    if (cur_state.draw.vertex_array == handle) {
 | 
			
		||||
        cur_state.draw.vertex_array = 0;
 | 
			
		||||
OpenGLState& OpenGLState::ResetBuffer(GLuint handle) {
 | 
			
		||||
    if (draw.vertex_buffer == handle) {
 | 
			
		||||
        draw.vertex_buffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (draw.uniform_buffer == handle) {
 | 
			
		||||
        draw.uniform_buffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OpenGLState::ResetFramebuffer(GLuint handle) {
 | 
			
		||||
    if (cur_state.draw.read_framebuffer == handle) {
 | 
			
		||||
        cur_state.draw.read_framebuffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (cur_state.draw.draw_framebuffer == handle) {
 | 
			
		||||
        cur_state.draw.draw_framebuffer = 0;
 | 
			
		||||
OpenGLState& OpenGLState::ResetVertexArray(GLuint handle) {
 | 
			
		||||
    if (draw.vertex_array == handle) {
 | 
			
		||||
        draw.vertex_array = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OpenGLState& OpenGLState::ResetFramebuffer(GLuint handle) {
 | 
			
		||||
    if (draw.read_framebuffer == handle) {
 | 
			
		||||
        draw.read_framebuffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    if (draw.draw_framebuffer == handle) {
 | 
			
		||||
        draw.draw_framebuffer = 0;
 | 
			
		||||
    }
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -122,27 +122,44 @@ public:
 | 
			
		||||
        GLuint vertex_buffer;    // GL_ARRAY_BUFFER_BINDING
 | 
			
		||||
        GLuint uniform_buffer;   // GL_UNIFORM_BUFFER_BINDING
 | 
			
		||||
        GLuint shader_program;   // GL_CURRENT_PROGRAM
 | 
			
		||||
        GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
 | 
			
		||||
    } draw;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        bool enabled; // GL_SCISSOR_TEST
 | 
			
		||||
        GLint x;
 | 
			
		||||
        GLint y;
 | 
			
		||||
        GLsizei width;
 | 
			
		||||
        GLsizei height;
 | 
			
		||||
    } scissor;
 | 
			
		||||
 | 
			
		||||
    struct {
 | 
			
		||||
        GLint x;
 | 
			
		||||
        GLint y;
 | 
			
		||||
        GLsizei width;
 | 
			
		||||
        GLsizei height;
 | 
			
		||||
    } viewport;
 | 
			
		||||
 | 
			
		||||
    std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
 | 
			
		||||
 | 
			
		||||
    OpenGLState();
 | 
			
		||||
 | 
			
		||||
    /// Get the currently active OpenGL state
 | 
			
		||||
    static const OpenGLState& GetCurState() {
 | 
			
		||||
    static OpenGLState GetCurState() {
 | 
			
		||||
        return cur_state;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Apply this state as the current OpenGL state
 | 
			
		||||
    void Apply() const;
 | 
			
		||||
 | 
			
		||||
    /// Resets and unbinds any references to the given resource in the current OpenGL state
 | 
			
		||||
    static void ResetTexture(GLuint handle);
 | 
			
		||||
    static void ResetSampler(GLuint handle);
 | 
			
		||||
    static void ResetProgram(GLuint handle);
 | 
			
		||||
    static void ResetBuffer(GLuint handle);
 | 
			
		||||
    static void ResetVertexArray(GLuint handle);
 | 
			
		||||
    static void ResetFramebuffer(GLuint handle);
 | 
			
		||||
    /// Resets any references to the given resource
 | 
			
		||||
    OpenGLState& ResetTexture(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetSampler(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetProgram(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetPipeline(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetBuffer(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetVertexArray(GLuint handle);
 | 
			
		||||
    OpenGLState& ResetFramebuffer(GLuint handle);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static OpenGLState cur_state;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										182
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,182 @@
 | 
			
		||||
// Copyright 2018 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <deque>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/alignment.h"
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_state.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
 | 
			
		||||
 | 
			
		||||
class OrphanBuffer : public OGLStreamBuffer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit OrphanBuffer(GLenum target) : OGLStreamBuffer(target) {}
 | 
			
		||||
    ~OrphanBuffer() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Create(size_t size, size_t sync_subdivide) override;
 | 
			
		||||
    void Release() override;
 | 
			
		||||
 | 
			
		||||
    std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
 | 
			
		||||
    void Unmap() override;
 | 
			
		||||
 | 
			
		||||
    std::vector<u8> data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class StorageBuffer : public OGLStreamBuffer {
 | 
			
		||||
public:
 | 
			
		||||
    explicit StorageBuffer(GLenum target) : OGLStreamBuffer(target) {}
 | 
			
		||||
    ~StorageBuffer() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void Create(size_t size, size_t sync_subdivide) override;
 | 
			
		||||
    void Release() override;
 | 
			
		||||
 | 
			
		||||
    std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) override;
 | 
			
		||||
    void Unmap() override;
 | 
			
		||||
 | 
			
		||||
    struct Fence {
 | 
			
		||||
        OGLSync sync;
 | 
			
		||||
        size_t offset;
 | 
			
		||||
    };
 | 
			
		||||
    std::deque<Fence> head;
 | 
			
		||||
    std::deque<Fence> tail;
 | 
			
		||||
 | 
			
		||||
    u8* mapped_ptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
OGLStreamBuffer::OGLStreamBuffer(GLenum target) {
 | 
			
		||||
    gl_target = target;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GLuint OGLStreamBuffer::GetHandle() const {
 | 
			
		||||
    return gl_buffer.handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::unique_ptr<OGLStreamBuffer> OGLStreamBuffer::MakeBuffer(bool storage_buffer, GLenum target) {
 | 
			
		||||
    if (storage_buffer) {
 | 
			
		||||
        return std::make_unique<StorageBuffer>(target);
 | 
			
		||||
    }
 | 
			
		||||
    return std::make_unique<OrphanBuffer>(target);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
OrphanBuffer::~OrphanBuffer() {
 | 
			
		||||
    Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Create(size_t size, size_t /*sync_subdivide*/) {
 | 
			
		||||
    buffer_pos = 0;
 | 
			
		||||
    buffer_size = size;
 | 
			
		||||
    data.resize(buffer_size);
 | 
			
		||||
 | 
			
		||||
    if (gl_buffer.handle == 0) {
 | 
			
		||||
        gl_buffer.Create();
 | 
			
		||||
        glBindBuffer(gl_target, gl_buffer.handle);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glBufferData(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr, GL_STREAM_DRAW);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Release() {
 | 
			
		||||
    gl_buffer.Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<u8*, GLintptr> OrphanBuffer::Map(size_t size, size_t alignment) {
 | 
			
		||||
    buffer_pos = Common::AlignUp(buffer_pos, alignment);
 | 
			
		||||
 | 
			
		||||
    if (buffer_pos + size > buffer_size) {
 | 
			
		||||
        Create(std::max(buffer_size, size), 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapped_size = size;
 | 
			
		||||
    return std::make_pair(&data[buffer_pos], static_cast<GLintptr>(buffer_pos));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void OrphanBuffer::Unmap() {
 | 
			
		||||
    glBufferSubData(gl_target, static_cast<GLintptr>(buffer_pos),
 | 
			
		||||
                    static_cast<GLsizeiptr>(mapped_size), &data[buffer_pos]);
 | 
			
		||||
    buffer_pos += mapped_size;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
StorageBuffer::~StorageBuffer() {
 | 
			
		||||
    Release();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Create(size_t size, size_t sync_subdivide) {
 | 
			
		||||
    if (gl_buffer.handle != 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    buffer_pos = 0;
 | 
			
		||||
    buffer_size = size;
 | 
			
		||||
    buffer_sync_subdivide = std::max<size_t>(sync_subdivide, 1);
 | 
			
		||||
 | 
			
		||||
    gl_buffer.Create();
 | 
			
		||||
    glBindBuffer(gl_target, gl_buffer.handle);
 | 
			
		||||
 | 
			
		||||
    glBufferStorage(gl_target, static_cast<GLsizeiptr>(buffer_size), nullptr,
 | 
			
		||||
                    GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT);
 | 
			
		||||
    mapped_ptr = reinterpret_cast<u8*>(
 | 
			
		||||
        glMapBufferRange(gl_target, 0, static_cast<GLsizeiptr>(buffer_size),
 | 
			
		||||
                         GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_FLUSH_EXPLICIT_BIT));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Release() {
 | 
			
		||||
    if (gl_buffer.handle == 0)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    glUnmapBuffer(gl_target);
 | 
			
		||||
 | 
			
		||||
    gl_buffer.Release();
 | 
			
		||||
    head.clear();
 | 
			
		||||
    tail.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::pair<u8*, GLintptr> StorageBuffer::Map(size_t size, size_t alignment) {
 | 
			
		||||
    ASSERT(size <= buffer_size);
 | 
			
		||||
 | 
			
		||||
    OGLSync sync;
 | 
			
		||||
 | 
			
		||||
    buffer_pos = Common::AlignUp(buffer_pos, alignment);
 | 
			
		||||
    size_t effective_offset = Common::AlignDown(buffer_pos, buffer_sync_subdivide);
 | 
			
		||||
 | 
			
		||||
    if (!head.empty() &&
 | 
			
		||||
        (effective_offset > head.back().offset || buffer_pos + size > buffer_size)) {
 | 
			
		||||
        ASSERT(head.back().sync.handle == 0);
 | 
			
		||||
        head.back().sync.Create();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (buffer_pos + size > buffer_size) {
 | 
			
		||||
        if (!tail.empty()) {
 | 
			
		||||
            std::swap(sync, tail.back().sync);
 | 
			
		||||
            tail.clear();
 | 
			
		||||
        }
 | 
			
		||||
        std::swap(tail, head);
 | 
			
		||||
        buffer_pos = 0;
 | 
			
		||||
        effective_offset = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!tail.empty() && buffer_pos + size > tail.front().offset) {
 | 
			
		||||
        std::swap(sync, tail.front().sync);
 | 
			
		||||
        tail.pop_front();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sync.handle != 0) {
 | 
			
		||||
        glClientWaitSync(sync.handle, GL_SYNC_FLUSH_COMMANDS_BIT, GL_TIMEOUT_IGNORED);
 | 
			
		||||
        sync.Release();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (head.empty() || effective_offset > head.back().offset) {
 | 
			
		||||
        head.emplace_back();
 | 
			
		||||
        head.back().offset = effective_offset;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mapped_size = size;
 | 
			
		||||
    return std::make_pair(&mapped_ptr[buffer_pos], static_cast<GLintptr>(buffer_pos));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void StorageBuffer::Unmap() {
 | 
			
		||||
    glFlushMappedBufferRange(gl_target, static_cast<GLintptr>(buffer_pos),
 | 
			
		||||
                             static_cast<GLsizeiptr>(mapped_size));
 | 
			
		||||
    buffer_pos += mapped_size;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										34
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/video_core/renderer_opengl/gl_stream_buffer.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,34 @@
 | 
			
		||||
// Copyright 2018 Citra Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
 | 
			
		||||
 | 
			
		||||
class OGLStreamBuffer : private NonCopyable {
 | 
			
		||||
public:
 | 
			
		||||
    explicit OGLStreamBuffer(GLenum target);
 | 
			
		||||
    virtual ~OGLStreamBuffer() = default;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    static std::unique_ptr<OGLStreamBuffer> MakeBuffer(bool storage_buffer, GLenum target);
 | 
			
		||||
 | 
			
		||||
    virtual void Create(size_t size, size_t sync_subdivide) = 0;
 | 
			
		||||
    virtual void Release() {}
 | 
			
		||||
 | 
			
		||||
    GLuint GetHandle() const;
 | 
			
		||||
 | 
			
		||||
    virtual std::pair<u8*, GLintptr> Map(size_t size, size_t alignment) = 0;
 | 
			
		||||
    virtual void Unmap() = 0;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    OGLBuffer gl_buffer;
 | 
			
		||||
    GLenum gl_target;
 | 
			
		||||
 | 
			
		||||
    size_t buffer_pos = 0;
 | 
			
		||||
    size_t buffer_size = 0;
 | 
			
		||||
    size_t buffer_sync_subdivide = 0;
 | 
			
		||||
    size_t mapped_size = 0;
 | 
			
		||||
};
 | 
			
		||||
@ -318,7 +318,7 @@ void RendererOpenGL::InitOpenGLObjects() {
 | 
			
		||||
                 0.0f);
 | 
			
		||||
 | 
			
		||||
    // Link shaders and get variable locations
 | 
			
		||||
    shader.Create(vertex_shader, fragment_shader);
 | 
			
		||||
    shader.Create(vertex_shader, nullptr, fragment_shader);
 | 
			
		||||
    state.draw.shader_program = shader.handle;
 | 
			
		||||
    state.Apply();
 | 
			
		||||
    uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user