@@ -4,7 +4,6 @@
|
|||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -26,6 +25,301 @@ static inline SphericalCoord get_forward_spherical_with_nearest(
|
|||||||
return Vector3ToSpherical(vec);
|
return Vector3ToSpherical(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ExternalTexturePipeline {
|
||||||
|
bool attempted_init;
|
||||||
|
bool ready;
|
||||||
|
GLuint program;
|
||||||
|
GLint sampler_loc;
|
||||||
|
GLuint vao;
|
||||||
|
GLuint vbo;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct ExternalTexturePipeline g_external_pipeline = { 0 };
|
||||||
|
|
||||||
|
static GLuint compile_shader(GLenum type, char const *source)
|
||||||
|
{
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
if (shader == 0) {
|
||||||
|
TraceLog(
|
||||||
|
LOG_ERROR, "Failed to create shader object for external texture");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
glShaderSource(shader, 1, &source, NULL);
|
||||||
|
glCompileShader(shader);
|
||||||
|
GLint status = GL_FALSE;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status != GL_TRUE) {
|
||||||
|
GLint log_len = 0;
|
||||||
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
|
||||||
|
if (log_len > 1) {
|
||||||
|
char *log = malloc((size_t)log_len);
|
||||||
|
if (log) {
|
||||||
|
glGetShaderInfoLog(shader, log_len, NULL, log);
|
||||||
|
TraceLog(LOG_ERROR,
|
||||||
|
"External texture shader compile failed: %s", log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glDeleteShader(shader);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ensure_external_pipeline(void)
|
||||||
|
{
|
||||||
|
if (g_external_pipeline.attempted_init)
|
||||||
|
return g_external_pipeline.ready;
|
||||||
|
|
||||||
|
g_external_pipeline.attempted_init = true;
|
||||||
|
|
||||||
|
static char const *vertex_src_300
|
||||||
|
= "#version 300 es\n"
|
||||||
|
"precision highp float;\n"
|
||||||
|
"layout(location = 0) in vec2 a_pos;\n"
|
||||||
|
"layout(location = 1) in vec2 a_uv;\n"
|
||||||
|
"out vec2 v_uv;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" v_uv = a_uv;\n"
|
||||||
|
" gl_Position = vec4(a_pos, 0.0, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static char const *fragment_src_300
|
||||||
|
= "#version 300 es\n"
|
||||||
|
"#extension GL_OES_EGL_image_external_essl3 : require\n"
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"in vec2 v_uv;\n"
|
||||||
|
"layout(location = 0) out vec4 fragColor;\n"
|
||||||
|
"uniform samplerExternalOES u_texture;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" fragColor = texture(u_texture, v_uv);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static char const *vertex_src_100
|
||||||
|
= "#version 100\n"
|
||||||
|
"attribute vec2 a_pos;\n"
|
||||||
|
"attribute vec2 a_uv;\n"
|
||||||
|
"varying vec2 v_uv;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" v_uv = a_uv;\n"
|
||||||
|
" gl_Position = vec4(a_pos, 0.0, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
static char const *fragment_src_100
|
||||||
|
= "#version 100\n"
|
||||||
|
"#extension GL_OES_EGL_image_external : require\n"
|
||||||
|
"precision mediump float;\n"
|
||||||
|
"varying vec2 v_uv;\n"
|
||||||
|
"uniform samplerExternalOES u_texture;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" gl_FragColor = texture2D(u_texture, v_uv);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
struct {
|
||||||
|
char const *vs;
|
||||||
|
char const *fs;
|
||||||
|
} const variants[] = {
|
||||||
|
{ vertex_src_300, fragment_src_300 },
|
||||||
|
{ vertex_src_100, fragment_src_100 },
|
||||||
|
};
|
||||||
|
|
||||||
|
GLuint program = 0;
|
||||||
|
GLint sampler_loc = -1;
|
||||||
|
size_t chosen_idx = (size_t)-1;
|
||||||
|
for (size_t i = 0; i < ARRAY_SZ(variants); ++i) {
|
||||||
|
GLuint vert = compile_shader(GL_VERTEX_SHADER, variants[i].vs);
|
||||||
|
if (vert == 0)
|
||||||
|
continue;
|
||||||
|
GLuint frag = compile_shader(GL_FRAGMENT_SHADER, variants[i].fs);
|
||||||
|
if (frag == 0) {
|
||||||
|
glDeleteShader(vert);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint prog = glCreateProgram();
|
||||||
|
if (prog == 0) {
|
||||||
|
TraceLog(LOG_ERROR,
|
||||||
|
"Failed to create shader program for external texture");
|
||||||
|
glDeleteShader(vert);
|
||||||
|
glDeleteShader(frag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glAttachShader(prog, vert);
|
||||||
|
glAttachShader(prog, frag);
|
||||||
|
glBindAttribLocation(prog, 0, "a_pos");
|
||||||
|
glBindAttribLocation(prog, 1, "a_uv");
|
||||||
|
glLinkProgram(prog);
|
||||||
|
GLint link_status = GL_FALSE;
|
||||||
|
glGetProgramiv(prog, GL_LINK_STATUS, &link_status);
|
||||||
|
if (link_status != GL_TRUE) {
|
||||||
|
GLint log_len = 0;
|
||||||
|
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_len);
|
||||||
|
if (log_len > 1) {
|
||||||
|
char *log = malloc((size_t)log_len);
|
||||||
|
if (log) {
|
||||||
|
glGetProgramInfoLog(prog, log_len, NULL, log);
|
||||||
|
TraceLog(LOG_ERROR,
|
||||||
|
"External texture program link failed: %s", log);
|
||||||
|
free(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glDeleteShader(vert);
|
||||||
|
glDeleteShader(frag);
|
||||||
|
glDeleteProgram(prog);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
glDetachShader(prog, vert);
|
||||||
|
glDetachShader(prog, frag);
|
||||||
|
glDeleteShader(vert);
|
||||||
|
glDeleteShader(frag);
|
||||||
|
|
||||||
|
sampler_loc = glGetUniformLocation(prog, "u_texture");
|
||||||
|
if (sampler_loc < 0) {
|
||||||
|
TraceLog(LOG_ERROR,
|
||||||
|
"External texture program missing u_texture uniform");
|
||||||
|
glDeleteProgram(prog);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
program = prog;
|
||||||
|
chosen_idx = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (chosen_idx == 1) {
|
||||||
|
TraceLog(
|
||||||
|
LOG_DEBUG, "External texture shader fallback to ESSL 100 variant");
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint vao = 0;
|
||||||
|
GLuint vbo = 0;
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
if (vao == 0 || vbo == 0) {
|
||||||
|
TraceLog(LOG_ERROR, "Failed to allocate buffers for external texture");
|
||||||
|
if (vao)
|
||||||
|
glDeleteVertexArrays(1, &vao);
|
||||||
|
if (vbo)
|
||||||
|
glDeleteBuffers(1, &vbo);
|
||||||
|
glDeleteProgram(program);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLint prev_vao = 0;
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prev_vao);
|
||||||
|
GLint prev_array_buffer = 0;
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prev_array_buffer);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(
|
||||||
|
0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (void *)0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4,
|
||||||
|
(void *)(sizeof(float) * 2));
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)prev_array_buffer);
|
||||||
|
glBindVertexArray((GLuint)prev_vao);
|
||||||
|
|
||||||
|
g_external_pipeline.program = program;
|
||||||
|
g_external_pipeline.sampler_loc = sampler_loc;
|
||||||
|
g_external_pipeline.vao = vao;
|
||||||
|
g_external_pipeline.vbo = vbo;
|
||||||
|
g_external_pipeline.ready = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool draw_external_texture(
|
||||||
|
struct wlr_gles2_texture_attribs const *attribs, int tex_width,
|
||||||
|
int tex_height, Rectangle src, Rectangle dst, int target_width,
|
||||||
|
int target_height)
|
||||||
|
{
|
||||||
|
if (!attribs || attribs->target != GL_TEXTURE_EXTERNAL_OES)
|
||||||
|
return false;
|
||||||
|
if (tex_width <= 0 || tex_height <= 0 || target_width <= 0
|
||||||
|
|| target_height <= 0)
|
||||||
|
return false;
|
||||||
|
if (!ensure_external_pipeline())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
rlDrawRenderBatchActive();
|
||||||
|
|
||||||
|
float x0 = dst.x;
|
||||||
|
float y0 = dst.y;
|
||||||
|
float x1 = dst.x + dst.width;
|
||||||
|
float y1 = dst.y + dst.height;
|
||||||
|
|
||||||
|
float ndc_x0 = (x0 / (float)target_width) * 2.0f - 1.0f;
|
||||||
|
float ndc_x1 = (x1 / (float)target_width) * 2.0f - 1.0f;
|
||||||
|
float ndc_y0 = 1.0f - (y0 / (float)target_height) * 2.0f;
|
||||||
|
float ndc_y1 = 1.0f - (y1 / (float)target_height) * 2.0f;
|
||||||
|
|
||||||
|
float inv_tex_w = 1.0f / (float)tex_width;
|
||||||
|
float inv_tex_h = 1.0f / (float)tex_height;
|
||||||
|
float u0 = src.x * inv_tex_w;
|
||||||
|
float v0 = src.y * inv_tex_h;
|
||||||
|
float u1 = (src.x + src.width) * inv_tex_w;
|
||||||
|
float v1 = (src.y + src.height) * inv_tex_h;
|
||||||
|
|
||||||
|
GLfloat vertices[] = {
|
||||||
|
ndc_x0,
|
||||||
|
ndc_y0,
|
||||||
|
u0,
|
||||||
|
v0,
|
||||||
|
ndc_x1,
|
||||||
|
ndc_y0,
|
||||||
|
u1,
|
||||||
|
v0,
|
||||||
|
ndc_x0,
|
||||||
|
ndc_y1,
|
||||||
|
u0,
|
||||||
|
v1,
|
||||||
|
ndc_x1,
|
||||||
|
ndc_y1,
|
||||||
|
u1,
|
||||||
|
v1,
|
||||||
|
};
|
||||||
|
|
||||||
|
GLint prev_program = 0;
|
||||||
|
glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program);
|
||||||
|
|
||||||
|
GLint prev_active_texture = 0;
|
||||||
|
glGetIntegerv(GL_ACTIVE_TEXTURE, &prev_active_texture);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
GLint prev_tex0_external = 0;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &prev_tex0_external);
|
||||||
|
GLint prev_tex0_2d = 0;
|
||||||
|
glGetIntegerv(GL_TEXTURE_BINDING_2D, &prev_tex0_2d);
|
||||||
|
|
||||||
|
GLint prev_array_buffer = 0;
|
||||||
|
glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &prev_array_buffer);
|
||||||
|
GLint prev_element_array_buffer = 0;
|
||||||
|
glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &prev_element_array_buffer);
|
||||||
|
GLint prev_vertex_array = 0;
|
||||||
|
glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &prev_vertex_array);
|
||||||
|
|
||||||
|
glUseProgram(g_external_pipeline.program);
|
||||||
|
glUniform1i(g_external_pipeline.sampler_loc, 0);
|
||||||
|
glBindTexture(GL_TEXTURE_EXTERNAL_OES, attribs->tex);
|
||||||
|
glBindVertexArray(g_external_pipeline.vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, g_external_pipeline.vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, (GLuint)prev_array_buffer);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (GLuint)prev_element_array_buffer);
|
||||||
|
glBindVertexArray((GLuint)prev_vertex_array);
|
||||||
|
glBindTexture(GL_TEXTURE_EXTERNAL_OES, (GLuint)prev_tex0_external);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, (GLuint)prev_tex0_2d);
|
||||||
|
glUseProgram((GLuint)prev_program);
|
||||||
|
glActiveTexture((GLenum)prev_active_texture);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void LunarWM_Toplevel_release_surface_rt(LunarWM_Toplevel *tl)
|
static void LunarWM_Toplevel_release_surface_rt(LunarWM_Toplevel *tl)
|
||||||
{
|
{
|
||||||
if (!tl)
|
if (!tl)
|
||||||
@@ -220,6 +514,36 @@ struct SurfaceComposeCtx {
|
|||||||
bool *has_alpha;
|
bool *has_alpha;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
char const *GLInternalFormatName(GLenum format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case GL_RGBA8:
|
||||||
|
return "GL_RGBA8";
|
||||||
|
case GL_RGB8:
|
||||||
|
return "GL_RGB8";
|
||||||
|
case GL_RGB565:
|
||||||
|
return "GL_RGB565";
|
||||||
|
case GL_RGBA4:
|
||||||
|
return "GL_RGBA4";
|
||||||
|
case GL_RGB5_A1:
|
||||||
|
return "GL_RGB5_A1";
|
||||||
|
case GL_DEPTH_COMPONENT16:
|
||||||
|
return "GL_DEPTH_COMPONENT16";
|
||||||
|
case GL_DEPTH_COMPONENT24:
|
||||||
|
return "GL_DEPTH_COMPONENT24";
|
||||||
|
case GL_DEPTH24_STENCIL8:
|
||||||
|
return "GL_DEPTH24_STENCIL8";
|
||||||
|
case GL_DEPTH32F_STENCIL8:
|
||||||
|
return "GL_DEPTH32F_STENCIL8";
|
||||||
|
case GL_R8:
|
||||||
|
return "GL_R8";
|
||||||
|
case GL_RG8:
|
||||||
|
return "GL_RG8";
|
||||||
|
default:
|
||||||
|
return "Unknown format";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void surface_compose_draw(
|
static void surface_compose_draw(
|
||||||
struct wlr_surface *surface, int sx, int sy, void *user_data)
|
struct wlr_surface *surface, int sx, int sy, void *user_data)
|
||||||
{
|
{
|
||||||
@@ -244,8 +568,7 @@ static void surface_compose_draw(
|
|||||||
.width = (int)wlr_tex->width,
|
.width = (int)wlr_tex->width,
|
||||||
.height = (int)wlr_tex->height,
|
.height = (int)wlr_tex->height,
|
||||||
.mipmaps = 1,
|
.mipmaps = 1,
|
||||||
.format = gles_tex->has_alpha
|
.format = gles_tex->has_alpha ? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
||||||
? PIXELFORMAT_UNCOMPRESSED_R8G8B8A8
|
|
||||||
: PIXELFORMAT_UNCOMPRESSED_R8G8B8,
|
: PIXELFORMAT_UNCOMPRESSED_R8G8B8,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -264,7 +587,20 @@ static void surface_compose_draw(
|
|||||||
dest_h,
|
dest_h,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (attribs.target == GL_TEXTURE_EXTERNAL_OES) {
|
||||||
|
static bool external_draw_warned = false;
|
||||||
|
if (!draw_external_texture(&attribs, tex.width, tex.height, src, dst,
|
||||||
|
ctx->extents.width, ctx->extents.height)) {
|
||||||
|
if (!external_draw_warned) {
|
||||||
|
TraceLog(LOG_WARNING,
|
||||||
|
"Failed to draw external texture, skipping frame");
|
||||||
|
external_draw_warned = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(attribs.target == GL_TEXTURE_2D);
|
||||||
DrawTexturePro(tex, src, dst, (Vector2) { 0.0f, 0.0f }, 0.0f, WHITE);
|
DrawTexturePro(tex, src, dst, (Vector2) { 0.0f, 0.0f }, 0.0f, WHITE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LunarWM_Toplevel_update(LunarWM_Toplevel *this)
|
bool LunarWM_Toplevel_update(LunarWM_Toplevel *this)
|
||||||
|
|||||||
Reference in New Issue
Block a user