forked from suyu/suyu
420cc13248
Add code required to use OpenGL assembly programs based on NV_gpu_program5. Decompilation for ARB programs is intended to be added in a follow up commit. This does **not** include ARB decompilation and it's not in an usable state. The intention behind assembly programs is to reduce shader stutter significantly on drivers supporting NV_gpu_program5 (and other required extensions). Currently only Nvidia's proprietary driver supports these extensions. Add a UI option hidden for now to avoid people enabling this option accidentally. This code path has some limitations that OpenGL compatibility doesn't have: - NV_shader_storage_buffer_object is limited to 16 entries for a single OpenGL context state (I don't know if this is an intended limitation, an specification issue or I am missing something). Currently causes issues on The Legend of Zelda: Link's Awakening. - NV_parameter_buffer_object can't bind buffers using an offset different to zero. The used workaround is to copy to a temporary buffer (this doesn't happen often so it's not an issue). On the other hand, it has the following advantages: - Shaders build a lot faster. - We have control over how floating point rounding is done over individual instructions (SPIR-V on Vulkan can't do this). - Operations on shared memory can be unsigned and signed. - Transform feedbacks are dynamic state (not yet implemented). - Parameter buffers (uniform buffers) are per stage, matching NVN and hardware's behavior. - The API to bind and create assembly programs makes sense, unlike ARB_separate_shader_objects.
310 lines
6.9 KiB
C++
310 lines
6.9 KiB
C++
// Copyright 2015 Citra Emulator Project
|
|
// Licensed under GPLv2 or any later version
|
|
// Refer to the license.txt file included.
|
|
|
|
#pragma once
|
|
|
|
#include <utility>
|
|
#include <glad/glad.h>
|
|
#include "common/common_types.h"
|
|
#include "video_core/renderer_opengl/gl_shader_util.h"
|
|
|
|
namespace OpenGL {
|
|
|
|
class OGLRenderbuffer : private NonCopyable {
|
|
public:
|
|
OGLRenderbuffer() = default;
|
|
|
|
OGLRenderbuffer(OGLRenderbuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLRenderbuffer() {
|
|
Release();
|
|
}
|
|
|
|
OGLRenderbuffer& operator=(OGLRenderbuffer&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLTexture : private NonCopyable {
|
|
public:
|
|
OGLTexture() = default;
|
|
|
|
OGLTexture(OGLTexture&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLTexture() {
|
|
Release();
|
|
}
|
|
|
|
OGLTexture& operator=(OGLTexture&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create(GLenum target);
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLTextureView : private NonCopyable {
|
|
public:
|
|
OGLTextureView() = default;
|
|
|
|
OGLTextureView(OGLTextureView&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLTextureView() {
|
|
Release();
|
|
}
|
|
|
|
OGLTextureView& operator=(OGLTextureView&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLSampler : private NonCopyable {
|
|
public:
|
|
OGLSampler() = default;
|
|
|
|
OGLSampler(OGLSampler&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLSampler() {
|
|
Release();
|
|
}
|
|
|
|
OGLSampler& operator=(OGLSampler&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLShader : private NonCopyable {
|
|
public:
|
|
OGLShader() = default;
|
|
|
|
OGLShader(OGLShader&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLShader() {
|
|
Release();
|
|
}
|
|
|
|
OGLShader& operator=(OGLShader&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
void Create(const char* source, GLenum type);
|
|
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLProgram : private NonCopyable {
|
|
public:
|
|
OGLProgram() = default;
|
|
|
|
OGLProgram(OGLProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLProgram() {
|
|
Release();
|
|
}
|
|
|
|
OGLProgram& operator=(OGLProgram&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
template <typename... T>
|
|
void Create(bool separable_program, bool hint_retrievable, T... shaders) {
|
|
if (handle != 0)
|
|
return;
|
|
handle = GLShader::LoadProgram(separable_program, hint_retrievable, shaders...);
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader,
|
|
bool separable_program = false, bool hint_retrievable = false);
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLAssemblyProgram : private NonCopyable {
|
|
public:
|
|
OGLAssemblyProgram() = default;
|
|
|
|
OGLAssemblyProgram(OGLAssemblyProgram&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLAssemblyProgram() {
|
|
Release();
|
|
}
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLPipeline : private NonCopyable {
|
|
public:
|
|
OGLPipeline() = default;
|
|
OGLPipeline(OGLPipeline&& o) noexcept : handle{std::exchange<GLuint>(o.handle, 0)} {}
|
|
|
|
~OGLPipeline() {
|
|
Release();
|
|
}
|
|
OGLPipeline& operator=(OGLPipeline&& o) noexcept {
|
|
handle = std::exchange<GLuint>(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLBuffer : private NonCopyable {
|
|
public:
|
|
OGLBuffer() = default;
|
|
|
|
OGLBuffer(OGLBuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLBuffer() {
|
|
Release();
|
|
}
|
|
|
|
OGLBuffer& operator=(OGLBuffer&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
// Converts the buffer into a stream copy buffer with a fixed size
|
|
void MakeStreamCopy(std::size_t buffer_size);
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLSync : private NonCopyable {
|
|
public:
|
|
OGLSync() = default;
|
|
|
|
OGLSync(OGLSync&& o) noexcept : handle(std::exchange(o.handle, nullptr)) {}
|
|
|
|
~OGLSync() {
|
|
Release();
|
|
}
|
|
OGLSync& operator=(OGLSync&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, nullptr);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLsync handle = 0;
|
|
};
|
|
|
|
class OGLFramebuffer : private NonCopyable {
|
|
public:
|
|
OGLFramebuffer() = default;
|
|
|
|
OGLFramebuffer(OGLFramebuffer&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLFramebuffer() {
|
|
Release();
|
|
}
|
|
|
|
OGLFramebuffer& operator=(OGLFramebuffer&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create();
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
class OGLQuery : private NonCopyable {
|
|
public:
|
|
OGLQuery() = default;
|
|
|
|
OGLQuery(OGLQuery&& o) noexcept : handle(std::exchange(o.handle, 0)) {}
|
|
|
|
~OGLQuery() {
|
|
Release();
|
|
}
|
|
|
|
OGLQuery& operator=(OGLQuery&& o) noexcept {
|
|
Release();
|
|
handle = std::exchange(o.handle, 0);
|
|
return *this;
|
|
}
|
|
|
|
/// Creates a new internal OpenGL resource and stores the handle
|
|
void Create(GLenum target);
|
|
|
|
/// Deletes the internal OpenGL resource
|
|
void Release();
|
|
|
|
GLuint handle = 0;
|
|
};
|
|
|
|
} // namespace OpenGL
|