(shader_gl_core.cpp) Simplify

This commit is contained in:
twinaphex 2019-04-24 20:25:37 +02:00
parent c85bf21fbb
commit 3225876f0b

View File

@ -92,6 +92,8 @@ GLuint gl_core_cross_compile_program(
GLuint program = 0; GLuint program = 0;
try try
{ {
spirv_cross::ShaderResources vertex_resources;
spirv_cross::ShaderResources fragment_resources;
spirv_cross::CompilerGLSL vertex_compiler(vertex, vertex_size / 4); spirv_cross::CompilerGLSL vertex_compiler(vertex, vertex_size / 4);
spirv_cross::CompilerGLSL fragment_compiler(fragment, fragment_size / 4); spirv_cross::CompilerGLSL fragment_compiler(fragment, fragment_size / 4);
spirv_cross::CompilerGLSL::Options opts; spirv_cross::CompilerGLSL::Options opts;
@ -105,11 +107,12 @@ GLuint gl_core_cross_compile_program(
opts.fragment.default_float_precision = spirv_cross::CompilerGLSL::Options::Precision::Highp; opts.fragment.default_float_precision = spirv_cross::CompilerGLSL::Options::Precision::Highp;
opts.fragment.default_int_precision = spirv_cross::CompilerGLSL::Options::Precision::Highp; opts.fragment.default_int_precision = spirv_cross::CompilerGLSL::Options::Precision::Highp;
opts.enable_420pack_extension = false; opts.enable_420pack_extension = false;
vertex_compiler.set_common_options(opts); vertex_compiler.set_common_options(opts);
fragment_compiler.set_common_options(opts); fragment_compiler.set_common_options(opts);
auto vertex_resources = vertex_compiler.get_shader_resources(); vertex_resources = vertex_compiler.get_shader_resources();
auto fragment_resources = fragment_compiler.get_shader_resources(); fragment_resources = fragment_compiler.get_shader_resources();
for (auto &res : vertex_resources.stage_inputs) for (auto &res : vertex_resources.stage_inputs)
{ {
@ -276,7 +279,7 @@ GLuint gl_core_cross_compile_program(
} }
} }
// Force proper bindings for textures. /* Force proper bindings for textures. */
for (auto &binding : texture_binding_fixups) for (auto &binding : texture_binding_fixups)
{ {
GLint location = glGetUniformLocation(program, (string("RARCH_TEXTURE_") + to_string(binding)).c_str()); GLint location = glGetUniformLocation(program, (string("RARCH_TEXTURE_") + to_string(binding)).c_str());
@ -320,7 +323,8 @@ static unsigned num_miplevels(unsigned width, unsigned height)
{ {
unsigned size = MAX(width, height); unsigned size = MAX(width, height);
unsigned levels = 0; unsigned levels = 0;
while (size) { while (size)
{
levels++; levels++;
size >>= 1; size >>= 1;
} }
@ -372,44 +376,44 @@ static gl_core_filter_chain_address wrap_to_address(gfx_wrap_type type)
{ {
switch (type) switch (type)
{ {
default:
case RARCH_WRAP_EDGE:
return GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_EDGE;
case RARCH_WRAP_BORDER: case RARCH_WRAP_BORDER:
return GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER; return GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER;
case RARCH_WRAP_REPEAT: case RARCH_WRAP_REPEAT:
return GL_CORE_FILTER_CHAIN_ADDRESS_REPEAT; return GL_CORE_FILTER_CHAIN_ADDRESS_REPEAT;
case RARCH_WRAP_MIRRORED_REPEAT: case RARCH_WRAP_MIRRORED_REPEAT:
return GL_CORE_FILTER_CHAIN_ADDRESS_MIRRORED_REPEAT; return GL_CORE_FILTER_CHAIN_ADDRESS_MIRRORED_REPEAT;
case RARCH_WRAP_EDGE:
default:
break;
} }
return GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_EDGE;
} }
static GLenum address_to_gl(gl_core_filter_chain_address type) static GLenum address_to_gl(gl_core_filter_chain_address type)
{ {
switch (type) switch (type)
{ {
default:
case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_EDGE:
return GL_CLAMP_TO_EDGE;
#ifdef HAVE_OPENGLES3 #ifdef HAVE_OPENGLES3
case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER: case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER:
//RARCH_WARN("[GLCore]: No CLAMP_TO_BORDER in GLES3. Falling back to edge clamp.\n"); #if 0
RARCH_WARN("[GLCore]: No CLAMP_TO_BORDER in GLES3. Falling back to edge clamp.\n");
#endif
return GL_CLAMP_TO_EDGE; return GL_CLAMP_TO_EDGE;
#else #else
case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER: case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_BORDER:
return GL_CLAMP_TO_BORDER; return GL_CLAMP_TO_BORDER;
#endif #endif
case GL_CORE_FILTER_CHAIN_ADDRESS_REPEAT: case GL_CORE_FILTER_CHAIN_ADDRESS_REPEAT:
return GL_REPEAT; return GL_REPEAT;
case GL_CORE_FILTER_CHAIN_ADDRESS_MIRRORED_REPEAT: case GL_CORE_FILTER_CHAIN_ADDRESS_MIRRORED_REPEAT:
return GL_MIRRORED_REPEAT; return GL_MIRRORED_REPEAT;
case GL_CORE_FILTER_CHAIN_ADDRESS_CLAMP_TO_EDGE:
default:
break;
} }
return GL_CLAMP_TO_EDGE;
} }
static GLenum convert_filter_to_mag_gl(gl_core_filter_chain_filter filter) static GLenum convert_filter_to_mag_gl(gl_core_filter_chain_filter filter)
@ -418,11 +422,12 @@ static GLenum convert_filter_to_mag_gl(gl_core_filter_chain_filter filter)
{ {
case GL_CORE_FILTER_CHAIN_LINEAR: case GL_CORE_FILTER_CHAIN_LINEAR:
return GL_LINEAR; return GL_LINEAR;
default:
case GL_CORE_FILTER_CHAIN_NEAREST: case GL_CORE_FILTER_CHAIN_NEAREST:
return GL_NEAREST; default:
break;
} }
return GL_NEAREST;
} }
static GLenum convert_filter_to_min_gl(gl_core_filter_chain_filter filter, gl_core_filter_chain_filter mipfilter) static GLenum convert_filter_to_min_gl(gl_core_filter_chain_filter filter, gl_core_filter_chain_filter mipfilter)
@ -433,7 +438,6 @@ static GLenum convert_filter_to_min_gl(gl_core_filter_chain_filter filter, gl_co
return GL_LINEAR_MIPMAP_NEAREST; return GL_LINEAR_MIPMAP_NEAREST;
else if (mipfilter == GL_CORE_FILTER_CHAIN_LINEAR) else if (mipfilter == GL_CORE_FILTER_CHAIN_LINEAR)
return GL_NEAREST_MIPMAP_LINEAR; return GL_NEAREST_MIPMAP_LINEAR;
else
return GL_NEAREST_MIPMAP_NEAREST; return GL_NEAREST_MIPMAP_NEAREST;
} }
@ -656,7 +660,7 @@ Framebuffer::Framebuffer(GLenum format_, unsigned max_levels_)
{ {
glGenFramebuffers(1, &framebuffer); glGenFramebuffers(1, &framebuffer);
// Need to bind to create. /* Need to bind to create */
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -729,12 +733,14 @@ void Framebuffer::init()
if (fallback) if (fallback)
{ {
unsigned levels;
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glDeleteTextures(1, &image); glDeleteTextures(1, &image);
glGenTextures(1, &image); glGenTextures(1, &image);
glBindTexture(GL_TEXTURE_2D, image); glBindTexture(GL_TEXTURE_2D, image);
unsigned levels = num_miplevels(size.width, size.height); levels = num_miplevels(size.width, size.height);
if (max_levels < levels) if (max_levels < levels)
levels = max_levels; levels = max_levels;
glTexStorage2D(GL_TEXTURE_2D, levels, glTexStorage2D(GL_TEXTURE_2D, levels,
@ -865,41 +871,38 @@ class UBORing
public: public:
~UBORing(); ~UBORing();
void init(size_t size, unsigned count); void init(size_t size, unsigned count);
void update_and_bind(unsigned vertex_binding, unsigned fragment_binding, const void *data, size_t size);
private:
std::vector<GLuint> buffers; std::vector<GLuint> buffers;
unsigned buffer_index = 0; unsigned buffer_index = 0;
}; };
void UBORing::init(size_t size, unsigned count) void UBORing::init(size_t size, unsigned count)
{ {
unsigned i;
buffers.resize(count); buffers.resize(count);
glGenBuffers(count, buffers.data()); glGenBuffers(count, buffers.data());
for (auto &buf : buffers)
for (i = 0; i < buffers.size(); i++)
{ {
glBindBuffer(GL_UNIFORM_BUFFER, buf); glBindBuffer(GL_UNIFORM_BUFFER, buffers[i]);
glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_STREAM_DRAW); glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_STREAM_DRAW);
} }
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
} }
void UBORing::update_and_bind(unsigned vertex_binding, unsigned fragment_binding, const void *data, size_t size) static void ubo_ring_update_and_bind(
unsigned vertex_binding,
unsigned fragment_binding,
const void *data, size_t size, GLuint id)
{ {
if (vertex_binding == GL_INVALID_INDEX && fragment_binding == GL_INVALID_INDEX) glBindBuffer(GL_UNIFORM_BUFFER, id);
return;
glBindBuffer(GL_UNIFORM_BUFFER, buffers[buffer_index]);
glBufferSubData(GL_UNIFORM_BUFFER, 0, size, data); glBufferSubData(GL_UNIFORM_BUFFER, 0, size, data);
glBindBuffer(GL_UNIFORM_BUFFER, 0); glBindBuffer(GL_UNIFORM_BUFFER, 0);
if (vertex_binding != GL_INVALID_INDEX) if (vertex_binding != GL_INVALID_INDEX)
glBindBufferBase(GL_UNIFORM_BUFFER, vertex_binding, buffers[buffer_index]); glBindBufferBase(GL_UNIFORM_BUFFER, vertex_binding, id);
if (fragment_binding != GL_INVALID_INDEX) if (fragment_binding != GL_INVALID_INDEX)
glBindBufferBase(GL_UNIFORM_BUFFER, fragment_binding, buffers[buffer_index]); glBindBufferBase(GL_UNIFORM_BUFFER, fragment_binding, id);
buffer_index++;
if (buffer_index >= buffers.size())
buffer_index = 0;
} }
UBORing::~UBORing() UBORing::~UBORing()
@ -1024,7 +1027,8 @@ private:
void set_semantic_texture(slang_texture_semantic semantic, void set_semantic_texture(slang_texture_semantic semantic,
const Texture &texture); const Texture &texture);
void set_semantic_texture_array(slang_texture_semantic semantic, unsigned index, void set_semantic_texture_array(slang_texture_semantic semantic,
unsigned index,
const Texture &texture); const Texture &texture);
slang_reflection reflection; slang_reflection reflection;
@ -1032,10 +1036,12 @@ private:
std::vector<uint8_t> uniforms; std::vector<uint8_t> uniforms;
void build_semantics(uint8_t *buffer, void build_semantics(uint8_t *buffer,
const float *mvp, const Texture &original, const Texture &source); const float *mvp,
const Texture &original, const Texture &source);
void build_semantic_vec4(uint8_t *data, slang_semantic semantic, void build_semantic_vec4(uint8_t *data, slang_semantic semantic,
unsigned width, unsigned height); unsigned width, unsigned height);
void build_semantic_uint(uint8_t *data, slang_semantic semantic, uint32_t value); void build_semantic_uint(uint8_t *data,
slang_semantic semantic, uint32_t value);
void build_semantic_parameter(uint8_t *data, unsigned index, float value); void build_semantic_parameter(uint8_t *data, unsigned index, float value);
void build_semantic_texture_vec4(uint8_t *data, void build_semantic_texture_vec4(uint8_t *data,
slang_texture_semantic semantic, slang_texture_semantic semantic,
@ -1046,7 +1052,8 @@ private:
void build_semantic_texture(uint8_t *buffer, void build_semantic_texture(uint8_t *buffer,
slang_texture_semantic semantic, const Texture &texture); slang_texture_semantic semantic, const Texture &texture);
void build_semantic_texture_array(uint8_t *buffer, void build_semantic_texture_array(uint8_t *buffer,
slang_texture_semantic semantic, unsigned index, const Texture &texture); slang_texture_semantic semantic,
unsigned index, const Texture &texture);
uint64_t frame_count = 0; uint64_t frame_count = 0;
unsigned frame_count_period = 0; unsigned frame_count_period = 0;
@ -1083,10 +1090,8 @@ bool Pass::build()
framebuffer_feedback.reset(); framebuffer_feedback.reset();
if (!final_pass) if (!final_pass)
{
framebuffer = unique_ptr<Framebuffer>( framebuffer = unique_ptr<Framebuffer>(
new Framebuffer(pass_info.rt_format, pass_info.max_levels)); new Framebuffer(pass_info.rt_format, pass_info.max_levels));
}
for (auto &param : parameters) for (auto &param : parameters)
{ {
@ -1173,38 +1178,44 @@ void Pass::reflect_parameter(const std::string &name, slang_texture_semantic_met
void Pass::reflect_parameter_array(const std::string &name, std::vector<slang_texture_semantic_meta> &meta) void Pass::reflect_parameter_array(const std::string &name, std::vector<slang_texture_semantic_meta> &meta)
{ {
for (size_t i = 0; i < meta.size(); i++) size_t i;
for (i = 0; i < meta.size(); i++)
{ {
auto n = name + std::to_string(i); std::string n = name + std::to_string(i);
auto &m = meta[i]; slang_texture_semantic_meta *m = (slang_texture_semantic_meta*)&meta[i];
if (m.uniform) if (m->uniform)
{ {
int vert = glGetUniformLocation(pipeline, (std::string("RARCH_UBO_VERTEX_INSTANCE.") + n).c_str()); int vert = glGetUniformLocation(pipeline,
int frag = glGetUniformLocation(pipeline, (std::string("RARCH_UBO_FRAGMENT_INSTANCE.") + n).c_str()); (std::string("RARCH_UBO_VERTEX_INSTANCE.") + n).c_str());
int frag = glGetUniformLocation(pipeline,
(std::string("RARCH_UBO_FRAGMENT_INSTANCE.") + n).c_str());
if (vert >= 0) if (vert >= 0)
m.location.ubo_vertex = vert; m->location.ubo_vertex = vert;
if (frag >= 0) if (frag >= 0)
m.location.ubo_fragment = frag; m->location.ubo_fragment = frag;
} }
if (m.push_constant) if (m->push_constant)
{ {
int vert = glGetUniformLocation(pipeline, (std::string("RARCH_PUSH_VERTEX_INSTANCE.") + n).c_str()); int vert = glGetUniformLocation(pipeline,
int frag = glGetUniformLocation(pipeline, (std::string("RARCH_PUSH_FRAGMENT_INSTANCE.") + n).c_str()); (std::string("RARCH_PUSH_VERTEX_INSTANCE.") + n).c_str());
int frag = glGetUniformLocation(pipeline,
(std::string("RARCH_PUSH_FRAGMENT_INSTANCE.") + n).c_str());
if (vert >= 0) if (vert >= 0)
m.location.push_vertex = vert; m->location.push_vertex = vert;
if (frag >= 0) if (frag >= 0)
m.location.push_fragment = frag; m->location.push_fragment = frag;
} }
} }
} }
bool Pass::init_pipeline() bool Pass::init_pipeline()
{ {
pipeline = gl_core_cross_compile_program(vertex_shader.data(), vertex_shader.size() * sizeof(uint32_t), pipeline = gl_core_cross_compile_program(
vertex_shader.data(), vertex_shader.size() * sizeof(uint32_t),
fragment_shader.data(), fragment_shader.size() * sizeof(uint32_t), fragment_shader.data(), fragment_shader.size() * sizeof(uint32_t),
&locations, false); &locations, false);
@ -1305,78 +1316,78 @@ void Pass::end_frame()
void Pass::build_semantic_vec4(uint8_t *data, slang_semantic semantic, void Pass::build_semantic_vec4(uint8_t *data, slang_semantic semantic,
unsigned width, unsigned height) unsigned width, unsigned height)
{ {
auto &refl = reflection.semantics[semantic]; slang_semantic_meta *refl = (slang_semantic_meta*)
&reflection.semantics[semantic];
if (data && refl.uniform) if (data && refl->uniform)
{ {
if (refl.location.ubo_vertex >= 0 || refl.location.ubo_fragment >= 0) if (refl->location.ubo_vertex >= 0 || refl->location.ubo_fragment >= 0)
{ {
float v4[4]; float v4[4];
build_vec4(v4, width, height); build_vec4(v4, width, height);
if (refl.location.ubo_vertex >= 0) if (refl->location.ubo_vertex >= 0)
glUniform4fv(refl.location.ubo_vertex, 1, v4); glUniform4fv(refl->location.ubo_vertex, 1, v4);
if (refl.location.ubo_fragment >= 0) if (refl->location.ubo_fragment >= 0)
glUniform4fv(refl.location.ubo_fragment, 1, v4); glUniform4fv(refl->location.ubo_fragment, 1, v4);
} }
else else
{
build_vec4( build_vec4(
reinterpret_cast<float *>(data + refl.ubo_offset), reinterpret_cast<float *>(data + refl->ubo_offset),
width, width,
height); height);
} }
}
if (refl.push_constant) if (refl->push_constant)
{ {
if (refl.location.push_vertex >= 0 || refl.location.push_fragment >= 0) if ( refl->location.push_vertex >= 0 ||
refl->location.push_fragment >= 0)
{ {
float v4[4]; float v4[4];
build_vec4(v4, width, height); build_vec4(v4, width, height);
if (refl.location.push_vertex >= 0) if (refl->location.push_vertex >= 0)
glUniform4fv(refl.location.push_vertex, 1, v4); glUniform4fv(refl->location.push_vertex, 1, v4);
if (refl.location.push_fragment >= 0) if (refl->location.push_fragment >= 0)
glUniform4fv(refl.location.push_fragment, 1, v4); glUniform4fv(refl->location.push_fragment, 1, v4);
} }
else else
{
build_vec4( build_vec4(
reinterpret_cast<float *>(push_constant_buffer.data() + refl.push_constant_offset), reinterpret_cast<float *>
(push_constant_buffer.data() + refl->push_constant_offset),
width, width,
height); height);
} }
} }
}
void Pass::build_semantic_parameter(uint8_t *data, unsigned index, float value) void Pass::build_semantic_parameter(uint8_t *data, unsigned index, float value)
{ {
auto &refl = reflection.semantic_float_parameters[index]; slang_semantic_meta *refl = (slang_semantic_meta*)
&reflection.semantic_float_parameters[index];
/* We will have filtered out stale parameters. */ /* We will have filtered out stale parameters. */
if (data && refl.uniform) if (data && refl->uniform)
{ {
if (refl.location.ubo_vertex >= 0 || refl.location.ubo_fragment >= 0) if (refl->location.ubo_vertex >= 0 || refl->location.ubo_fragment >= 0)
{ {
if (refl.location.ubo_vertex >= 0) if (refl->location.ubo_vertex >= 0)
glUniform1f(refl.location.ubo_vertex, value); glUniform1f(refl->location.ubo_vertex, value);
if (refl.location.ubo_fragment >= 0) if (refl->location.ubo_fragment >= 0)
glUniform1f(refl.location.ubo_fragment, value); glUniform1f(refl->location.ubo_fragment, value);
} }
else else
*reinterpret_cast<float *>(data + refl.ubo_offset) = value; *reinterpret_cast<float *>(data + refl->ubo_offset) = value;
} }
if (refl.push_constant) if (refl->push_constant)
{ {
if (refl.location.push_vertex >= 0 || refl.location.push_fragment >= 0) if (refl->location.push_vertex >= 0 || refl->location.push_fragment >= 0)
{ {
if (refl.location.push_vertex >= 0) if (refl->location.push_vertex >= 0)
glUniform1f(refl.location.push_vertex, value); glUniform1f(refl->location.push_vertex, value);
if (refl.location.push_fragment >= 0) if (refl->location.push_fragment >= 0)
glUniform1f(refl.location.push_fragment, value); glUniform1f(refl->location.push_fragment, value);
} }
else else
*reinterpret_cast<float *>(push_constant_buffer.data() + refl.push_constant_offset) = value; *reinterpret_cast<float *>(push_constant_buffer.data() + refl->push_constant_offset) = value;
} }
} }
@ -1448,13 +1459,11 @@ void Pass::build_semantic_texture_array_vec4(uint8_t *data, slang_texture_semant
glUniform4fv(refl[index].location.ubo_fragment, 1, v4); glUniform4fv(refl[index].location.ubo_fragment, 1, v4);
} }
else else
{
build_vec4( build_vec4(
reinterpret_cast<float *>(data + refl[index].ubo_offset), reinterpret_cast<float *>(data + refl[index].ubo_offset),
width, width,
height); height);
} }
}
if (refl[index].push_constant) if (refl[index].push_constant)
{ {
@ -1468,14 +1477,12 @@ void Pass::build_semantic_texture_array_vec4(uint8_t *data, slang_texture_semant
glUniform4fv(refl[index].location.push_fragment, 1, v4); glUniform4fv(refl[index].location.push_fragment, 1, v4);
} }
else else
{
build_vec4( build_vec4(
reinterpret_cast<float *>(push_constant_buffer.data() + refl[index].push_constant_offset), reinterpret_cast<float *>(push_constant_buffer.data() + refl[index].push_constant_offset),
width, width,
height); height);
} }
} }
}
void Pass::build_semantic_texture_vec4(uint8_t *data, slang_texture_semantic semantic, void Pass::build_semantic_texture_vec4(uint8_t *data, slang_texture_semantic semantic,
unsigned width, unsigned height) unsigned width, unsigned height)
@ -1549,87 +1556,85 @@ void Pass::build_semantic_texture_array(uint8_t *buffer,
void Pass::build_semantics(uint8_t *buffer, void Pass::build_semantics(uint8_t *buffer,
const float *mvp, const Texture &original, const Texture &source) const float *mvp, const Texture &original, const Texture &source)
{ {
unsigned i;
/* MVP */ /* MVP */
if (buffer && reflection.semantics[SLANG_SEMANTIC_MVP].uniform) if (buffer && reflection.semantics[SLANG_SEMANTIC_MVP].uniform)
{ {
size_t offset = reflection.semantics[SLANG_SEMANTIC_MVP].ubo_offset; size_t offset = reflection.semantics[
SLANG_SEMANTIC_MVP].ubo_offset;
if (mvp) if (mvp)
memcpy(buffer + offset, mvp, sizeof(float) * 16); memcpy(buffer + offset,
mvp, sizeof(float) * 16);
else else
build_default_matrix(reinterpret_cast<float *>(buffer + offset)); build_default_matrix(reinterpret_cast<float *>(
buffer + offset));
} }
if (reflection.semantics[SLANG_SEMANTIC_MVP].push_constant) if (reflection.semantics[SLANG_SEMANTIC_MVP].push_constant)
{ {
size_t offset = reflection.semantics[SLANG_SEMANTIC_MVP].push_constant_offset; size_t offset = reflection.semantics[
SLANG_SEMANTIC_MVP].push_constant_offset;
if (mvp) if (mvp)
memcpy(push_constant_buffer.data() + offset, mvp, sizeof(float) * 16); memcpy(push_constant_buffer.data() + offset,
mvp, sizeof(float) * 16);
else else
build_default_matrix(reinterpret_cast<float *>(push_constant_buffer.data() + offset)); build_default_matrix(reinterpret_cast<float *>(
push_constant_buffer.data() + offset));
} }
/* Output information */ /* Output information */
build_semantic_vec4(buffer, SLANG_SEMANTIC_OUTPUT, build_semantic_vec4(buffer, SLANG_SEMANTIC_OUTPUT,
current_framebuffer_size.width, current_framebuffer_size.height); current_framebuffer_size.width,
current_framebuffer_size.height);
build_semantic_vec4(buffer, SLANG_SEMANTIC_FINAL_VIEWPORT, build_semantic_vec4(buffer, SLANG_SEMANTIC_FINAL_VIEWPORT,
unsigned(current_viewport.width), unsigned(current_viewport.height)); unsigned(current_viewport.width),
unsigned(current_viewport.height));
build_semantic_uint(buffer, SLANG_SEMANTIC_FRAME_COUNT, build_semantic_uint(buffer, SLANG_SEMANTIC_FRAME_COUNT,
frame_count_period ? uint32_t(frame_count % frame_count_period) : uint32_t(frame_count)); frame_count_period
? uint32_t(frame_count % frame_count_period)
: uint32_t(frame_count));
/* Standard inputs */ /* Standard inputs */
build_semantic_texture(buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL, original); build_semantic_texture(buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL, original);
build_semantic_texture(buffer, SLANG_TEXTURE_SEMANTIC_SOURCE, source); build_semantic_texture(buffer, SLANG_TEXTURE_SEMANTIC_SOURCE, source);
/* ORIGINAL_HISTORY[0] is an alias of ORIGINAL. */ /* ORIGINAL_HISTORY[0] is an alias of ORIGINAL. */
build_semantic_texture_array(buffer, SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, 0, original); build_semantic_texture_array(buffer,
SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, 0, original);
/* Parameters. */ /* Parameters. */
for (auto &param : filtered_parameters) for (i = 0; i < filtered_parameters.size(); i++)
{ build_semantic_parameter(buffer,
float value = common->shader_preset->parameters[param.index].current; filtered_parameters[i].semantic_index,
build_semantic_parameter(buffer, param.semantic_index, value); common->shader_preset->parameters[
} filtered_parameters[i].index].current);
/* Previous inputs. */ /* Previous inputs. */
unsigned i = 0; for (i = 0; i < common->original_history.size(); i++)
for (auto &texture : common->original_history)
{
build_semantic_texture_array(buffer, build_semantic_texture_array(buffer,
SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, i + 1, SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY, i + 1,
texture); common->original_history[i]);
i++;
}
/* Previous passes. */ /* Previous passes. */
i = 0; for (i = 0; i < common->pass_outputs.size(); i++)
for (auto &texture : common->pass_outputs)
{
build_semantic_texture_array(buffer, build_semantic_texture_array(buffer,
SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT, i, SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT, i,
texture); common->pass_outputs[i]);
i++;
}
/* Feedback FBOs. */ /* Feedback FBOs. */
i = 0; for (i = 0; i < common->framebuffer_feedback.size(); i++)
for (auto &texture : common->framebuffer_feedback)
{
build_semantic_texture_array(buffer, build_semantic_texture_array(buffer,
SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK, i, SLANG_TEXTURE_SEMANTIC_PASS_FEEDBACK, i,
texture); common->framebuffer_feedback[i]);
i++;
}
/* LUTs. */ /* LUTs. */
i = 0; for (i = 0; i < common->luts.size(); i++)
for (auto &lut : common->luts)
{
build_semantic_texture_array(buffer, build_semantic_texture_array(buffer,
SLANG_TEXTURE_SEMANTIC_USER, i, SLANG_TEXTURE_SEMANTIC_USER, i,
lut->get_texture()); common->luts[i]->get_texture());
i++;
}
} }
void Pass::build_commands( void Pass::build_commands(
@ -1639,16 +1644,15 @@ void Pass::build_commands(
const float *mvp) const float *mvp)
{ {
current_viewport = vp; current_viewport = vp;
auto size = get_output_size( Size2D size = get_output_size(
{ original.texture.width, original.texture.height }, { original.texture.width, original.texture.height },
{ source.texture.width, source.texture.height }); { source.texture.width, source.texture.height });
if (framebuffer && if (framebuffer &&
(size.width != framebuffer->get_size().width || (size.width != framebuffer->get_size().width ||
size.height != framebuffer->get_size().height)) size.height != framebuffer->get_size().height))
{
framebuffer->set_size(size); framebuffer->set_size(size);
}
current_framebuffer_size = size; current_framebuffer_size = size;
glUseProgram(pipeline); glUseProgram(pipeline);
@ -1656,35 +1660,39 @@ void Pass::build_commands(
build_semantics(uniforms.data(), mvp, original, source); build_semantics(uniforms.data(), mvp, original, source);
if (locations.flat_ubo_vertex >= 0) if (locations.flat_ubo_vertex >= 0)
{
glUniform4fv(locations.flat_ubo_vertex, glUniform4fv(locations.flat_ubo_vertex,
GLsizei((reflection.ubo_size + 15) / 16), GLsizei((reflection.ubo_size + 15) / 16),
reinterpret_cast<const float *>(uniforms.data())); reinterpret_cast<const float *>(uniforms.data()));
}
if (locations.flat_ubo_fragment >= 0) if (locations.flat_ubo_fragment >= 0)
{
glUniform4fv(locations.flat_ubo_fragment, glUniform4fv(locations.flat_ubo_fragment,
GLsizei((reflection.ubo_size + 15) / 16), GLsizei((reflection.ubo_size + 15) / 16),
reinterpret_cast<const float *>(uniforms.data())); reinterpret_cast<const float *>(uniforms.data()));
}
if (locations.flat_push_vertex >= 0) if (locations.flat_push_vertex >= 0)
{
glUniform4fv(locations.flat_push_vertex, glUniform4fv(locations.flat_push_vertex,
GLsizei((reflection.push_constant_size + 15) / 16), GLsizei((reflection.push_constant_size + 15) / 16),
reinterpret_cast<const float *>(push_constant_buffer.data())); reinterpret_cast<const float *>(push_constant_buffer.data()));
}
if (locations.flat_push_fragment >= 0) if (locations.flat_push_fragment >= 0)
{
glUniform4fv(locations.flat_push_fragment, glUniform4fv(locations.flat_push_fragment,
GLsizei((reflection.push_constant_size + 15) / 16), GLsizei((reflection.push_constant_size + 15) / 16),
reinterpret_cast<const float *>(push_constant_buffer.data())); reinterpret_cast<const float *>(push_constant_buffer.data()));
}
ubo_ring.update_and_bind(locations.buffer_index_ubo_vertex, locations.buffer_index_ubo_fragment, if (!( locations.buffer_index_ubo_vertex == GL_INVALID_INDEX
uniforms.data(), reflection.ubo_size); && locations.buffer_index_ubo_fragment == GL_INVALID_INDEX))
{
ubo_ring_update_and_bind(
locations.buffer_index_ubo_vertex,
locations.buffer_index_ubo_fragment,
uniforms.data(), reflection.ubo_size,
ubo_ring.buffers[ubo_ring.buffer_index]
);
ubo_ring.buffer_index++;
if (ubo_ring.buffer_index >= ubo_ring.buffers.size())
ubo_ring.buffer_index = 0;
}
/* The final pass is always executed inside /* The final pass is always executed inside
* another render pass since the frontend will * another render pass since the frontend will
@ -1699,14 +1707,10 @@ void Pass::build_commands(
} }
if (final_pass) if (final_pass)
{
glViewport(current_viewport.x, current_viewport.y, glViewport(current_viewport.x, current_viewport.y,
current_viewport.width, current_viewport.height); current_viewport.width, current_viewport.height);
}
else else
{
glViewport(0, 0, size.width, size.height); glViewport(0, 0, size.width, size.height);
}
#ifndef HAVE_OPENGLES3 #ifndef HAVE_OPENGLES3
if (framebuffer && framebuffer->get_format() == GL_SRGB8_ALPHA8) if (framebuffer && framebuffer->get_format() == GL_SRGB8_ALPHA8)
@ -1723,21 +1727,16 @@ void Pass::build_commands(
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
if (!final_pass) if (!final_pass)
{
if (framebuffer->get_levels() > 1) if (framebuffer->get_levels() > 1)
framebuffer->generate_mips(); framebuffer->generate_mips();
} }
}
} }
struct gl_core_filter_chain struct gl_core_filter_chain
{ {
public: public:
gl_core_filter_chain(unsigned num_passes) gl_core_filter_chain(unsigned num_passes) { set_num_passes(num_passes); }
{
set_num_passes(num_passes);
}
inline void set_shader_preset(unique_ptr<video_shader> shader) inline void set_shader_preset(unique_ptr<video_shader> shader)
{ {
@ -1795,7 +1794,7 @@ void gl_core_filter_chain::clear_history_and_feedback()
texture->clear(); texture->clear();
for (auto &pass : passes) for (auto &pass : passes)
{ {
auto *fb = pass->get_feedback_framebuffer(); gl_core::Framebuffer *fb = pass->get_feedback_framebuffer();
if (fb) if (fb)
fb->clear(); fb->clear();
} }
@ -1803,44 +1802,55 @@ void gl_core_filter_chain::clear_history_and_feedback()
void gl_core_filter_chain::update_history_info() void gl_core_filter_chain::update_history_info()
{ {
unsigned i = 0; unsigned i;
for (auto &texture : original_history) for (i = 0; i < original_history.size(); i++)
{ {
auto &source = common.original_history[i]; gl_core::Texture *source = (gl_core::Texture*)
source.texture.image = texture->get_image(); &common.original_history[i];
source.texture.width = texture->get_size().width;
source.texture.height = texture->get_size().height; if (!source)
source.filter = passes.front()->get_source_filter(); continue;
source.mip_filter = passes.front()->get_mip_filter();
source.address = passes.front()->get_address_mode(); source->texture.image = original_history[i]->get_image();
i++; source->texture.width = original_history[i]->get_size().width;
source->texture.height = original_history[i]->get_size().height;
source->filter = passes.front()->get_source_filter();
source->mip_filter = passes.front()->get_mip_filter();
source->address = passes.front()->get_address_mode();
} }
} }
void gl_core_filter_chain::update_feedback_info() void gl_core_filter_chain::update_feedback_info()
{ {
unsigned i;
if (common.framebuffer_feedback.empty()) if (common.framebuffer_feedback.empty())
return; return;
for (unsigned i = 0; i < passes.size() - 1; i++) for (i = 0; i < passes.size() - 1; i++)
{ {
auto fb = passes[i]->get_feedback_framebuffer(); gl_core::Framebuffer *fb = passes[i]->get_feedback_framebuffer();
if (!fb) if (!fb)
continue; continue;
auto &source = common.framebuffer_feedback[i]; gl_core::Texture *source = (gl_core::Texture*)
source.texture.image = fb->get_image(); &common.framebuffer_feedback[i];
source.texture.width = fb->get_size().width;
source.texture.height = fb->get_size().height; if (!source)
source.filter = passes[i]->get_source_filter(); continue;
source.mip_filter = passes[i]->get_mip_filter();
source.address = passes[i]->get_address_mode(); source->texture.image = fb->get_image();
source->texture.width = fb->get_size().width;
source->texture.height = fb->get_size().height;
source->filter = passes[i]->get_source_filter();
source->mip_filter = passes[i]->get_mip_filter();
source->address = passes[i]->get_address_mode();
} }
} }
void gl_core_filter_chain::build_offscreen_passes(const gl_core_viewport &vp) void gl_core_filter_chain::build_offscreen_passes(const gl_core_viewport &vp)
{ {
/* First frame, make sure our history and feedback textures are in a clean state. */ /* First frame, make sure our history and feedback textures
* are in a clean state. */
if (require_clear) if (require_clear)
{ {
clear_history_and_feedback(); clear_history_and_feedback();
@ -1863,6 +1873,7 @@ void gl_core_filter_chain::build_offscreen_passes(const gl_core_viewport &vp)
passes[i]->build_commands(original, source, vp, nullptr); passes[i]->build_commands(original, source, vp, nullptr);
auto &fb = passes[i]->get_framebuffer(); auto &fb = passes[i]->get_framebuffer();
source.texture.image = fb.get_image(); source.texture.image = fb.get_image();
source.texture.width = fb.get_size().width; source.texture.width = fb.get_size().width;
source.texture.height = fb.get_size().height; source.texture.height = fb.get_size().height;
@ -1883,9 +1894,7 @@ void gl_core_filter_chain::update_history()
if (input_texture.width != tmp->get_size().width || if (input_texture.width != tmp->get_size().width ||
input_texture.height != tmp->get_size().height || input_texture.height != tmp->get_size().height ||
(input_texture.format != 0 && input_texture.format != tmp->get_format())) (input_texture.format != 0 && input_texture.format != tmp->get_format()))
{
tmp->set_size({ input_texture.width, input_texture.height }, input_texture.format); tmp->set_size({ input_texture.width, input_texture.height }, input_texture.format);
}
tmp->copy(common, input_texture.image); tmp->copy(common, input_texture.image);
@ -1901,14 +1910,13 @@ void gl_core_filter_chain::end_frame()
* pass is the last that reads from * pass is the last that reads from
* the history and dispatch the copy earlier. */ * the history and dispatch the copy earlier. */
if (!original_history.empty()) if (!original_history.empty())
{
update_history(); update_history();
} }
}
void gl_core_filter_chain::build_viewport_pass( void gl_core_filter_chain::build_viewport_pass(
const gl_core_viewport &vp, const float *mvp) const gl_core_viewport &vp, const float *mvp)
{ {
unsigned i;
/* First frame, make sure our history and feedback textures are in a clean state. */ /* First frame, make sure our history and feedback textures are in a clean state. */
if (require_clear) if (require_clear)
{ {
@ -1947,22 +1955,23 @@ void gl_core_filter_chain::build_viewport_pass(
passes.back()->build_commands(original, source, vp, mvp); passes.back()->build_commands(original, source, vp, mvp);
/* For feedback FBOs, swap current and previous. */ /* For feedback FBOs, swap current and previous. */
for (auto &pass : passes) for (i = 0; i < passes.size(); i++)
pass->end_frame(); passes[i]->end_frame();
} }
bool gl_core_filter_chain::init_history() bool gl_core_filter_chain::init_history()
{ {
unsigned i;
size_t required_images = 0;
original_history.clear(); original_history.clear();
common.original_history.clear(); common.original_history.clear();
size_t required_images = 0; for (i = 0; i < passes.size(); i++)
for (auto &pass : passes)
{
required_images = required_images =
max(required_images, max(required_images,
pass->get_reflection().semantic_textures[SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY].size()); passes[i]->get_reflection().semantic_textures[
} SLANG_TEXTURE_SEMANTIC_ORIGINAL_HISTORY].size());
if (required_images < 2) if (required_images < 2)
{ {
@ -1976,10 +1985,8 @@ bool gl_core_filter_chain::init_history()
original_history.reserve(required_images); original_history.reserve(required_images);
common.original_history.resize(required_images); common.original_history.resize(required_images);
for (unsigned i = 0; i < required_images; i++) for (i = 0; i < required_images; i++)
{
original_history.emplace_back(new gl_core::Framebuffer(0, 1)); original_history.emplace_back(new gl_core::Framebuffer(0, 1));
}
RARCH_LOG("[GLCore]: Using history of %u frames.\n", unsigned(required_images)); RARCH_LOG("[GLCore]: Using history of %u frames.\n", unsigned(required_images));
@ -1993,12 +2000,13 @@ bool gl_core_filter_chain::init_history()
bool gl_core_filter_chain::init_feedback() bool gl_core_filter_chain::init_feedback()
{ {
common.framebuffer_feedback.clear(); unsigned i;
bool use_feedbacks = false; bool use_feedbacks = false;
common.framebuffer_feedback.clear();
/* Final pass cannot have feedback. */ /* Final pass cannot have feedback. */
for (unsigned i = 0; i < passes.size() - 1; i++) for (i = 0; i < passes.size() - 1; i++)
{ {
bool use_feedback = false; bool use_feedback = false;
for (auto &pass : passes) for (auto &pass : passes)
@ -2085,9 +2093,12 @@ void gl_core_filter_chain::set_pass_info(unsigned pass, const gl_core_filter_cha
void gl_core_filter_chain::set_num_passes(unsigned num_passes) void gl_core_filter_chain::set_num_passes(unsigned num_passes)
{ {
unsigned i;
pass_info.resize(num_passes); pass_info.resize(num_passes);
passes.reserve(num_passes); passes.reserve(num_passes);
for (unsigned i = 0; i < num_passes; i++)
for (i = 0; i < num_passes; i++)
{ {
passes.emplace_back(new gl_core::Pass(i + 1 == num_passes)); passes.emplace_back(new gl_core::Pass(i + 1 == num_passes));
passes.back()->set_common_resources(&common); passes.back()->set_common_resources(&common);
@ -2107,10 +2118,12 @@ void gl_core_filter_chain::add_parameter(unsigned pass, unsigned index, const st
bool gl_core_filter_chain::init() bool gl_core_filter_chain::init()
{ {
unsigned i;
if (!init_alias()) if (!init_alias())
return false; return false;
for (unsigned i = 0; i < passes.size(); i++) for (i = 0; i < passes.size(); i++)
{ {
auto &pass = passes[i]; auto &pass = passes[i];
RARCH_LOG("[slang]: Building pass #%u (%s)\n", i, RARCH_LOG("[slang]: Building pass #%u (%s)\n", i,
@ -2137,8 +2150,8 @@ void gl_core_filter_chain::set_input_texture(
{ {
input_texture = texture; input_texture = texture;
// Need a copy to remove padding. /* Need a copy to remove padding.
// GL HW render interface in libretro is kinda garbage now ... * GL HW render interface in libretro is kinda garbage now ... */
if (input_texture.padded_width != input_texture.width || if (input_texture.padded_width != input_texture.width ||
input_texture.padded_height != input_texture.height) input_texture.padded_height != input_texture.height)
{ {
@ -2148,9 +2161,7 @@ void gl_core_filter_chain::set_input_texture(
if (input_texture.width != copy_framebuffer->get_size().width || if (input_texture.width != copy_framebuffer->get_size().width ||
input_texture.height != copy_framebuffer->get_size().height || input_texture.height != copy_framebuffer->get_size().height ||
(input_texture.format != 0 && input_texture.format != copy_framebuffer->get_format())) (input_texture.format != 0 && input_texture.format != copy_framebuffer->get_format()))
{
copy_framebuffer->set_size({ input_texture.width, input_texture.height }, input_texture.format); copy_framebuffer->set_size({ input_texture.width, input_texture.height }, input_texture.format);
}
copy_framebuffer->copy_partial(common, input_texture.image, copy_framebuffer->copy_partial(common, input_texture.image,
float(input_texture.width) / input_texture.padded_width, float(input_texture.width) / input_texture.padded_width,
@ -2184,6 +2195,7 @@ static unique_ptr<gl_core::StaticTexture> gl_core_filter_chain_load_lut(
gl_core_filter_chain *chain, gl_core_filter_chain *chain,
const video_shader_lut *shader) const video_shader_lut *shader)
{ {
GLuint tex = 0;
texture_image image = {}; texture_image image = {};
image.supports_rgba = true; image.supports_rgba = true;
@ -2191,7 +2203,7 @@ static unique_ptr<gl_core::StaticTexture> gl_core_filter_chain_load_lut(
return {}; return {};
unsigned levels = shader->mipmap ? gl_core::num_miplevels(image.width, image.height) : 1; unsigned levels = shader->mipmap ? gl_core::num_miplevels(image.width, image.height) : 1;
GLuint tex = 0;
glGenTextures(1, &tex); glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex); glBindTexture(GL_TEXTURE_2D, tex);
glTexStorage2D(GL_TEXTURE_2D, levels, glTexStorage2D(GL_TEXTURE_2D, levels,
@ -2222,7 +2234,8 @@ static bool gl_core_filter_chain_load_luts(
gl_core_filter_chain *chain, gl_core_filter_chain *chain,
video_shader *shader) video_shader *shader)
{ {
for (unsigned i = 0; i < shader->luts; i++) unsigned i;
for (i = 0; i < shader->luts; i++)
{ {
auto image = gl_core_filter_chain_load_lut(chain, &shader->lut[i]); auto image = gl_core_filter_chain_load_lut(chain, &shader->lut[i]);
if (!image) if (!image)