201 lines
5.7 KiB
C
201 lines
5.7 KiB
C
/*
|
|
* This software is licensed under the terms of the MIT License.
|
|
* See COPYING for further information.
|
|
* ---
|
|
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
|
|
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
|
|
*/
|
|
|
|
#include "fbcopy_fallback.h"
|
|
|
|
#include "util.h"
|
|
|
|
static ShaderProgram *blit_shader;
|
|
static struct {
|
|
Uniform *outputs_enabled;
|
|
Uniform *depth_enabled;
|
|
Uniform *input_depth;
|
|
Uniform *input_colors[FRAMEBUFFER_MAX_COLOR_ATTACHMENTS];
|
|
} blit_uniforms;
|
|
|
|
void gles30_fbcopyfallback_init(void) {
|
|
StringBuffer sbuf = {};
|
|
|
|
strbuf_printf(&sbuf,
|
|
"#version 300 es\n"
|
|
"precision highp float;\n"
|
|
"precision highp int;\n"
|
|
"uniform int outputs_enabled[%i];\n"
|
|
"uniform int depth_enabled;\n"
|
|
"uniform sampler2D input_depth;\n"
|
|
"layout(location = 0) out vec4 outputs[%i];\n",
|
|
FRAMEBUFFER_MAX_COLOR_ATTACHMENTS, FRAMEBUFFER_MAX_COLOR_ATTACHMENTS
|
|
);
|
|
|
|
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
|
strbuf_printf(&sbuf, "uniform sampler2D input_color%i;\n", i);
|
|
}
|
|
|
|
strbuf_cat(&sbuf,
|
|
"void main(void) {\n"
|
|
" ivec2 tc = ivec2(gl_FragCoord.xy);\n"
|
|
);
|
|
|
|
// FIXME: do something about mipmaps?
|
|
|
|
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
|
strbuf_printf(&sbuf,
|
|
" if(outputs_enabled[%i] != 0) "
|
|
"outputs[%i] = texelFetch(input_color%i, tc, 0);\n", i, i, i);
|
|
}
|
|
|
|
strbuf_cat(&sbuf,
|
|
" if(depth_enabled != 0) "
|
|
"gl_FragDepth = texelFetch(input_depth, tc, 0).r;\n"
|
|
"}\n");
|
|
|
|
ShaderSource frag_src = {
|
|
.content = sbuf.start,
|
|
.content_size = sbuf.pos - sbuf.start,
|
|
.lang.lang = SHLANG_GLSL,
|
|
.lang.glsl.version = { 300, GLSL_PROFILE_ES },
|
|
.stage = SHADER_STAGE_FRAGMENT,
|
|
};
|
|
|
|
log_info("\n%s\n ", frag_src.content);
|
|
|
|
ShaderObject *frag_shobj = r_shader_object_compile(&frag_src);
|
|
strbuf_free(&sbuf);
|
|
|
|
if(!frag_shobj) {
|
|
log_fatal("Failed to compile internal blit fragment shader");
|
|
}
|
|
|
|
static const char vert_src_str[] =
|
|
"#version 300 es\n"
|
|
"uniform vec4 r_viewport;\n"
|
|
"vec2 verts[4] = vec2[](\n"
|
|
" vec2( 1.0, -1.0),\n"
|
|
" vec2( 1.0, 1.0),\n"
|
|
" vec2(-1.0, -1.0),\n"
|
|
" vec2(-1.0, 1.0)\n"
|
|
");\n"
|
|
"void main(void) {\n"
|
|
" gl_Position = vec4(verts[gl_VertexID], 0, 1);\n"
|
|
"}\n";
|
|
|
|
ShaderSource vert_src = {
|
|
.content = (char*)vert_src_str,
|
|
.content_size = sizeof(vert_src_str),
|
|
.lang.lang = SHLANG_GLSL,
|
|
.lang.glsl.version = { 300, GLSL_PROFILE_ES },
|
|
.stage = SHADER_STAGE_VERTEX,
|
|
};
|
|
|
|
ShaderObject *vert_shobj = r_shader_object_compile(&vert_src);
|
|
|
|
strbuf_free(&sbuf);
|
|
|
|
if(!vert_shobj) {
|
|
log_fatal("Failed to compile internal blit vertex shader");
|
|
}
|
|
|
|
if(!(blit_shader = r_shader_program_link(2, (ShaderObject*[]) { vert_shobj, frag_shobj }))) {
|
|
log_fatal("Failed to link internal blit shader");
|
|
}
|
|
|
|
r_shader_object_destroy(vert_shobj);
|
|
r_shader_object_destroy(frag_shobj);
|
|
|
|
blit_uniforms.outputs_enabled = NOT_NULL(r_shader_uniform(blit_shader, "outputs_enabled"));
|
|
blit_uniforms.depth_enabled = NOT_NULL(r_shader_uniform(blit_shader, "depth_enabled"));
|
|
blit_uniforms.input_depth = NOT_NULL(r_shader_uniform(blit_shader, "input_depth"));
|
|
|
|
for(int i = 0; i < ARRAY_SIZE(blit_uniforms.input_colors); ++i) {
|
|
char tmp[64];
|
|
snprintf(tmp, sizeof(tmp), "input_color%i", i);
|
|
blit_uniforms.input_colors[i] = NOT_NULL(r_shader_uniform(blit_shader, tmp));
|
|
}
|
|
}
|
|
|
|
void gles30_fbcopyfallback_shutdown(void) {
|
|
r_shader_program_destroy(blit_shader);
|
|
}
|
|
|
|
void gles30_fbcopyfallback_framebuffer_copy(Framebuffer *dst, Framebuffer *src, BufferKindFlags flags) {
|
|
int u_outputs_enabled[FRAMEBUFFER_MAX_COLOR_ATTACHMENTS] = {};
|
|
Texture *u_inputs[FRAMEBUFFER_MAX_COLOR_ATTACHMENTS] = {};
|
|
Texture *u_input_depth = NULL;
|
|
bool any_enabled = false;
|
|
|
|
if(flags & BUFFER_DEPTH) {
|
|
Texture *depth_src = r_framebuffer_get_attachment(src, FRAMEBUFFER_ATTACH_DEPTH);
|
|
if(depth_src && r_framebuffer_get_attachment(dst, FRAMEBUFFER_ATTACH_DEPTH)) {
|
|
u_input_depth = depth_src;
|
|
any_enabled = true;
|
|
}
|
|
}
|
|
|
|
if(flags & BUFFER_COLOR) {
|
|
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
|
FramebufferAttachment a = FRAMEBUFFER_ATTACH_COLOR0 + i;
|
|
Texture *csrc = r_framebuffer_get_attachment(src, a);
|
|
if(csrc && r_framebuffer_get_attachment(dst, a)) {
|
|
u_inputs[i] = csrc;
|
|
u_outputs_enabled[i] = 1;
|
|
any_enabled = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!any_enabled) {
|
|
return;
|
|
}
|
|
|
|
FramebufferAttachment outputmap_saved[FRAMEBUFFER_MAX_OUTPUTS];
|
|
r_framebuffer_get_output_attachments(dst, outputmap_saved);
|
|
|
|
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
|
if(u_outputs_enabled[i]) {
|
|
r_framebuffer_set_output_attachment(dst, i, FRAMEBUFFER_ATTACH_COLOR0 + i);
|
|
} else {
|
|
r_framebuffer_set_output_attachment(dst, i, FRAMEBUFFER_ATTACH_NONE);
|
|
}
|
|
}
|
|
|
|
FloatRect viewport_saved;
|
|
r_framebuffer_viewport_current(dst, &viewport_saved);
|
|
IntExtent fbsize = r_framebuffer_get_size(dst);
|
|
r_framebuffer_viewport(dst, 0, 0, fbsize.w, fbsize.h);
|
|
r_state_push();
|
|
|
|
r_blend(BLEND_NONE);
|
|
r_scissor(0, 0, fbsize.w, fbsize.h);
|
|
r_disable(RCAP_CULL_FACE);
|
|
|
|
if(u_input_depth) {
|
|
r_enable(RCAP_DEPTH_TEST);
|
|
r_enable(RCAP_DEPTH_WRITE);
|
|
r_depth_func(DEPTH_ALWAYS);
|
|
} else {
|
|
r_disable(RCAP_DEPTH_TEST);
|
|
}
|
|
|
|
r_framebuffer(dst);
|
|
r_shader_ptr(blit_shader);
|
|
|
|
r_uniform_int_array(blit_uniforms.outputs_enabled, 0, ARRAY_SIZE(u_outputs_enabled), u_outputs_enabled);
|
|
r_uniform_int(blit_uniforms.depth_enabled, u_input_depth != NULL);
|
|
r_uniform_sampler(blit_uniforms.input_depth, u_input_depth);
|
|
|
|
for(int i = 0; i < FRAMEBUFFER_MAX_COLOR_ATTACHMENTS; ++i) {
|
|
r_uniform_sampler(blit_uniforms.input_colors[i], u_inputs[i]);
|
|
}
|
|
|
|
// FIXME draw without changing VAO somehow
|
|
r_draw(r_model_get_quad()->vertex_array, PRIM_TRIANGLE_STRIP, 0, 4, 0, 0);
|
|
|
|
r_state_pop();
|
|
r_framebuffer_set_output_attachments(dst, outputmap_saved);
|
|
r_framebuffer_viewport_rect(dst, viewport_saved);
|
|
}
|