Skip to content
Commits on Source (28)
......@@ -24,7 +24,6 @@
#include <stdint.h>
#include <inttypes.h>
#include "config.h"
#include "config_internal.h"
#include "pl_assert.h"
......@@ -35,6 +34,7 @@
// as being externally visible. (Otherwise, all symbols are hidden by default)
#pragma GCC visibility push(default)
#include "config.h"
#include "include/libplacebo/colorspace.h"
#include "include/libplacebo/common.h"
#include "include/libplacebo/context.h"
......
......@@ -71,19 +71,35 @@ struct pl_context *pl_context_create(int api_ver,
pthread_mutex_lock(&pl_ctx_mutex);
if (pl_ctx_refcount++ == 0)
global_init();
pthread_mutex_unlock(&pl_ctx_mutex);
struct pl_context *ctx = talloc_zero(NULL, struct pl_context);
ctx->params = *PL_DEF(params, &pl_context_default_params);
int err = pthread_mutex_init(&ctx->lock, NULL);
if (err != 0) {
fprintf(stderr, "Failed initializing pthread mutex: %s\n", strerror(err));
pl_ctx_refcount--;
talloc_free(ctx);
ctx = NULL;
}
pthread_mutex_unlock(&pl_ctx_mutex);
pl_info(ctx, "Initialized libplacebo %s (API v%d)", PL_VERSION, PL_API_VER);
return ctx;
}
const struct pl_context_params pl_context_default_params = {0};
void pl_context_destroy(struct pl_context **ctx)
void pl_context_destroy(struct pl_context **pctx)
{
TA_FREEP(ctx);
struct pl_context *ctx = *pctx;
if (!ctx)
return;
pthread_mutex_lock(&ctx->lock);
pthread_mutex_destroy(&ctx->lock);
talloc_free(ctx);
*pctx = NULL;
// Do global uninitialization only when refcount reaches 0
pthread_mutex_lock(&pl_ctx_mutex);
......@@ -95,7 +111,9 @@ void pl_context_destroy(struct pl_context **ctx)
void pl_context_update(struct pl_context *ctx,
const struct pl_context_params *params)
{
pthread_mutex_lock(&ctx->lock);
ctx->params = *PL_DEF(params, &pl_context_default_params);
pthread_mutex_unlock(&ctx->lock);
}
static FILE *default_stream(void *stream, enum pl_log_level level)
......@@ -148,12 +166,26 @@ void pl_msg(struct pl_context *ctx, enum pl_log_level lev, const char *fmt, ...)
void pl_msg_va(struct pl_context *ctx, enum pl_log_level lev, const char *fmt,
va_list va)
{
// Test log message without taking the lock, to avoid thrashing the
// lock for thousands of trace messages unless those are actually
// enabled. This may be a false negative, in which case log messages may
// be lost as a result. But this shouldn't be a big deal, since any
// situation leading to lost log messages would itself be a race condition.
if (!pl_msg_test(ctx, lev))
return;
// Re-test the log message level with held lock to avoid false positives,
// which would be a considerably bigger deal than false negatives
pthread_mutex_lock(&ctx->lock);
if (!pl_msg_test(ctx, lev))
goto done;
ctx->logbuffer.len = 0;
bstr_xappend_vasprintf(ctx, &ctx->logbuffer, fmt, va);
ctx->params.log_cb(ctx->params.log_priv, lev, ctx->logbuffer.start);
done:
pthread_mutex_unlock(&ctx->lock);
}
void pl_msg_source(struct pl_context *ctx, enum pl_log_level lev, const char *src)
......
......@@ -18,16 +18,24 @@
#pragma once
#include <stdarg.h>
#include <pthread.h>
#include "common.h"
struct pl_context {
struct pl_context_params params;
struct bstr logbuffer;
pthread_mutex_t lock;
// Provide a place for implementations to track suppression of errors
// FIXME: This is a hack. Get rid of it ASAP. It's also not thread-safe.
uint64_t suppress_errors_for_object;
};
// Logging-related functions
// Warning: Not entirely thread-safe. Exercise caution when using. May result
// in either false positives or false negatives. Make sure to re-run this
// function while `ctx->lock` is held, to ensure no race conditions on the
// check.
static inline bool pl_msg_test(struct pl_context *ctx, enum pl_log_level lev)
{
return ctx->params.log_cb && ctx->params.log_level >= lev;
......
......@@ -65,7 +65,6 @@ struct pass_var {
struct pass {
uint64_t signature; // as returned by pl_shader_signature
const struct pl_pass *pass;
bool failed;
// contains cached data and update metadata, same order as pl_shader
struct pass_var *vars;
......@@ -303,12 +302,19 @@ static void generate_shaders(struct pl_dispatch *dp, struct pass *pass,
ADD(pre, "#extension GL_OES_EGL_image_external : enable\n");
if (gpu->glsl.gles) {
ADD(pre, "precision mediump float;\n");
ADD(pre, "precision mediump sampler2D;\n");
// Use 32-bit precision for floats if possible
ADD(pre, "#ifdef GL_FRAGMENT_PRECISION_HIGH \n"
"precision highp float; \n"
"#else \n"
"precision mediump float; \n"
"#endif \n");
// Always use 16-bit precision for samplers
ADD(pre, "precision mediump sampler2D; \n");
if (gpu->limits.max_tex_1d_dim)
ADD(pre, "precision mediump sampler1D;\n");
ADD(pre, "precision mediump sampler1D; \n");
if (gpu->limits.max_tex_3d_dim && gpu->glsl.version > 100)
ADD(pre, "precision mediump sampler3D;\n");
ADD(pre, "precision mediump sampler3D; \n");
}
char *vert_in = gpu->glsl.version >= 130 ? "in" : "attribute";
......@@ -589,17 +595,18 @@ static struct pass *find_pass(struct pl_dispatch *dp, struct pl_shader *sh,
void *tmp = talloc_new(NULL); // for resources attached to `params`
struct pass *pass = talloc_zero(dp, struct pass);
pass->signature = sig;
pass->ubo_desc = (struct pl_shader_desc) {
.desc = {
.name = "UBO",
.type = PL_DESC_BUF_UNIFORM,
struct pass *pass = talloc_ptrtype(dp, pass);
*pass = (struct pass) {
.signature = sig,
.ubo_desc = {
.desc = {
.name = "UBO",
.type = PL_DESC_BUF_UNIFORM,
},
},
};
struct pl_shader_res *res = &sh->res;
struct pl_pass_run_params *rparams = &pass->run_params;
struct pl_pass_params params = {
.type = pl_shader_is_compute(sh) ? PL_PASS_COMPUTE : PL_PASS_RASTER,
......@@ -1050,7 +1057,7 @@ bool pl_dispatch_compute(struct pl_dispatch *dp,
struct pass *pass = find_pass(dp, sh, NULL, NULL, NULL, false);
// Silently return on failed passes
if (pass->failed)
if (!pass->pass)
goto error;
struct pl_pass_run_params *rparams = &pass->run_params;
......
......@@ -15,6 +15,8 @@
* License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config_internal.h"
#include <assert.h>
#include <pthread.h>
......@@ -23,23 +25,29 @@ extern "C" {
}
#include <glslang/Include/ResourceLimits.h>
#include <glslang/Include/revision.h>
#include <glslang/Public/ShaderLang.h>
#include <SPIRV/GlslangToSpv.h>
#include "glslang.h"
#define GLSLANG_VERSION_CHECK(major, minor, patch) \
(((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \
(((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \
((patch) <= GLSLANG_VERSION_PATCH)))))
using namespace glslang;
static pthread_mutex_t pl_glslang_mutex = PTHREAD_MUTEX_INITIALIZER;
static int pl_glslang_refcount;
int pl_glslang_version()
int pl_glslang_version(void)
{
return GLSLANG_PATCH_LEVEL;
return (GLSLANG_VERSION_MAJOR & 0xFF) << 24 |
(GLSLANG_VERSION_MINOR & 0xFF) << 16 |
(GLSLANG_VERSION_PATCH & 0xFFFF);
}
bool pl_glslang_init()
bool pl_glslang_init(void)
{
bool ret = true;
......@@ -51,7 +59,7 @@ bool pl_glslang_init()
return ret;
}
void pl_glslang_uninit()
void pl_glslang_uninit(void)
{
pthread_mutex_lock(&pl_glslang_mutex);
if (--pl_glslang_refcount == 0)
......@@ -78,7 +86,7 @@ struct pl_glslang_res *pl_glslang_compile(const char *glsl, uint32_t api_ver,
if (api_ver >= EShTargetVulkan_1_1)
spirv_version = EShTargetSpv_1_3;
#if GLSLANG_PATCH_LEVEL >= 3667
#if GLSLANG_VERSION_CHECK(0, 0, 3667)
if (api_ver >= EShTargetVulkan_1_2)
spirv_version = EShTargetSpv_1_5;
#endif
......@@ -200,7 +208,7 @@ const TBuiltInResource DefaultTBuiltInResource = {
/* .MaxCullDistances = */ 8,
/* .MaxCombinedClipAndCullDistances = */ 8,
/* .MaxSamples = */ 4,
#if GLSLANG_PATCH_LEVEL >= 2892
#if GLSLANG_VERSION_CHECK(0, 0, 2892)
/* .maxMeshOutputVerticesNV = */ 256,
/* .maxMeshOutputPrimitivesNV = */ 512,
/* .maxMeshWorkGroupSizeX_NV = */ 32,
......@@ -211,6 +219,9 @@ const TBuiltInResource DefaultTBuiltInResource = {
/* .maxTaskWorkGroupSizeZ_NV = */ 1,
/* .maxMeshViewCountNV = */ 4,
#endif
#if GLSLANG_VERSION_CHECK(0, 0, 3763)
/* .maxDualSourceDrawBuffersEXT = */ 1,
#endif
/* .limits = */ {
/* .nonInductiveForLoops = */ 1,
......
......@@ -24,9 +24,9 @@
extern "C" {
#endif
int pl_glslang_version();
bool pl_glslang_init();
void pl_glslang_uninit();
int pl_glslang_version(void);
bool pl_glslang_init(void);
void pl_glslang_uninit(void);
struct pl_glslang_res {
// Compilation status
......
......@@ -175,13 +175,14 @@ bool pl_lcms_compute_lut(struct pl_context *ctx, enum pl_rendering_intent intent
goto error;
cmsSetLogErrorHandlerTHR(cms, error_callback);
dstp = get_profile(ctx, cms, dst, NULL, &out->src_color);
srcp = get_profile(ctx, cms, src, dstp, &out->dst_color);
dstp = get_profile(ctx, cms, dst, NULL, &out->dst_color);
srcp = get_profile(ctx, cms, src, dstp, &out->src_color);
if (!srcp || !dstp)
goto error;
uint32_t flags = cmsFLAGS_HIGHRESPRECALC | cmsFLAGS_BLACKPOINTCOMPENSATION |
cmsFLAGS_NOCACHE;
uint32_t flags = cmsFLAGS_HIGHRESPRECALC | cmsFLAGS_BLACKPOINTCOMPENSATION;
trafo = cmsCreateTransformTHR(cms, srcp, TYPE_RGB_16, dstp, TYPE_RGBA_FLT,
intent, flags);
if (!trafo)
......
......@@ -49,7 +49,7 @@ endif
# work-arounds for glslang braindeath
glslang_combined = disabler()
glslang_min_ver = 2763
glslang_min_ver = '>=0.0.2763'
glslang_req = get_option('glslang')
if glslang_req.auto() and shaderc.found()
......@@ -71,8 +71,10 @@ else
]
glslang_opt_deps = [
cxx.find_library('SPIRV-Tools', required: false),
cxx.find_library('SPIRV-Tools-opt', required: false),
cxx.find_library('GenericCodeGen', required: false),
cxx.find_library('MachineIndependent', required: false),
cxx.find_library('SPIRV-Tools', required: false),
cxx.find_library('SPIRV-Tools-opt', required: false),
]
glslang_found = true
......@@ -83,11 +85,38 @@ else
endif
if glslang_found
glslang_ver = cxx.get_define('GLSLANG_PATCH_LEVEL',
prefix: '#include <glslang/Include/revision.h>'
).to_int()
glslang_header_old = 'glslang/Include/revision.h'
glslang_header_new = 'glslang/build_info.h'
if cc.has_header(glslang_header_new)
glslang_ver_major = cxx.get_define('GLSLANG_VERSION_MAJOR',
prefix: '#include <' + glslang_header_new + '>'
).to_int()
glslang_ver_minor = cxx.get_define('GLSLANG_VERSION_MINOR',
prefix: '#include <' + glslang_header_new + '>'
).to_int()
glslang_ver_patch = cxx.get_define('GLSLANG_VERSION_PATCH',
prefix: '#include <' + glslang_header_new + '>'
).to_int()
elif cc.has_header(glslang_header_old)
# This is technically incorrect, but since we don't care about major
# versions for this version range, it's an acceptable substitute
glslang_ver_major = 0
glslang_ver_minor = 0
glslang_ver_patch = cxx.get_define('GLSLANG_PATCH_LEVEL',
prefix: '#include <' + glslang_header_old+ '>'
).to_int()
else
error('No glslang version header found?')
endif
if glslang_ver >= glslang_min_ver
glslang_ver = '@0@.@1@.@2@'.format(
glslang_ver_major,
glslang_ver_minor,
glslang_ver_patch,
)
if glslang_ver.version_compare(glslang_min_ver)
# glslang must be linked against pthreads on platforms where pthreads is
# available. Because of their horrible architecture, gcc can't do it
# automatically, and for some reason dependency('threads') (which uses
......@@ -108,8 +137,12 @@ if glslang_found
add_project_arguments('-I' + i, language: 'cpp')
endforeach
conf_internal.set('GLSLANG_VERSION_MAJOR', glslang_ver_major)
conf_internal.set('GLSLANG_VERSION_MINOR', glslang_ver_minor)
conf_internal.set('GLSLANG_VERSION_PATCH', glslang_ver_patch)
else
error('glslang revision @0@ too old! Must be at least @1@'
error('glslang version @0@ too old! Must be at least @1@'
.format(glslang_ver, glslang_min_ver))
endif
endif
......@@ -209,6 +242,7 @@ components = [
]
defs = ''
pc_vars = []
comps = configuration_data()
foreach c : components
......@@ -219,6 +253,7 @@ foreach c : components
if deps.found()
defs += '#define PL_HAVE_@0@ 1\n'.format(pretty)
pc_vars += 'pl_has_@0@=1'.format(pretty.to_lower())
comps.set(name, 1)
build_deps += deps
sources += c.get('srcs', [])
......@@ -226,6 +261,7 @@ foreach c : components
tests += c.get('test', [])
else
defs += '#undef PL_HAVE_@0@\n'.format(pretty)
pc_vars += 'pl_has_@0@=0'.format(pretty.to_lower())
endif
endforeach
......@@ -240,8 +276,10 @@ if comps.has('vulkan')
if get_option('vulkan-link')
defs += '#define PL_HAVE_VK_PROC_ADDR 1'
pc_vars += 'pl_has_vk_proc_addr=1'
else
defs += '#undef PL_HAVE_VK_PROC_ADDR'
pc_vars += 'pl_has_vk_proc_addr=0'
endif
endif
......@@ -315,6 +353,7 @@ pkg.generate(
description: 'Reusable library for GPU-accelerated video/image rendering',
libraries: lib,
version: version,
variables: pc_vars,
)
......
......@@ -76,6 +76,20 @@ const struct pl_opengl *pl_opengl_create(struct pl_context *ctx,
PL_INFO(p, " GL_VENDOR: %s", glGetString(GL_VENDOR));
PL_INFO(p, " GL_RENDERER: %s", glGetString(GL_RENDERER));
if (pl_msg_test(ctx, PL_LOG_DEBUG)) {
if (ver >= 30) {
int num_exts = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &num_exts);
PL_DEBUG(p, " GL_EXTENSIONS:");
for (int i = 0; i < num_exts; i++) {
const char *ext = glGetStringi(GL_EXTENSIONS, i);
PL_DEBUG(p, " %s", ext);
}
} else {
PL_DEBUG(p, " GL_EXTENSIONS: %s", glGetString(GL_EXTENSIONS));
}
}
if (params->debug) {
if (epoxy_has_gl_extension("GL_ARB_debug_output")) {
glDebugMessageCallback(debug_cb, ctx);
......
......@@ -29,7 +29,8 @@ struct pl_gl {
int gl_ver;
int gles_ver;
bool has_stride;
bool has_invalidate;
bool has_invalidate_fb;
bool has_invalidate_tex;
bool has_vao;
bool has_queries;
};
......@@ -267,7 +268,8 @@ const struct pl_gpu *pl_gpu_create_gl(struct pl_context *ctx)
// Cached some existing capability checks
p->has_stride = test_ext(gpu, "GL_EXT_unpack_subimage", 11, 30);
p->has_vao = test_ext(gpu, "GL_ARB_vertex_array_object", 30, 0);
p->has_invalidate = test_ext(gpu, "GL_ARB_invalidate_subdata", 43, 30);
p->has_invalidate_fb = test_ext(gpu, "GL_ARB_invalidate_subdata", 43, 30);
p->has_invalidate_tex = test_ext(gpu, "GL_ARB_invalidate_subdata", 43, 0);
p->has_queries = test_ext(gpu, "GL_ARB_timer_query", 33, 0);
// We simply don't know, so make up some values
......@@ -443,22 +445,22 @@ static const struct pl_tex *gl_tex_create(const struct pl_gpu *gpu,
}
glGenFramebuffers(1, &tex_gl->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex_gl->fbo);
switch (dims) {
case 1:
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_1D, tex_gl->texture, 0);
break;
case 2:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tex_gl->texture, 0);
break;
case 3: abort();
}
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
GLenum err = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
if (err != GL_FRAMEBUFFER_COMPLETE) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
PL_ERR(gpu, "Failed creating framebuffer: error code %d", err);
goto error;
}
......@@ -468,7 +470,7 @@ static const struct pl_tex *gl_tex_create(const struct pl_gpu *gpu,
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &read_type);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &read_fmt);
if (read_type != tex_gl->type || read_fmt != tex_gl->format) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
PL_ERR(gpu, "Trying to create host_readable texture whose "
"implementation-defined pixel read format "
"(type=0x%X, fmt=0x%X) does not match the texture's "
......@@ -480,7 +482,7 @@ static const struct pl_tex *gl_tex_create(const struct pl_gpu *gpu,
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (!gl_check_err(gpu, "gl_tex_create: fbo"))
goto error;
}
......@@ -500,14 +502,14 @@ static bool gl_fb_query(const struct pl_gpu *gpu, int fbo, struct pl_fmt *fmt)
if (!fbo && p->gles_ver && p->gles_ver < 30)
goto fallback; // can't query default framebuffer on GLES 2.0
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
GLenum obj = p->gles_ver ? GL_BACK : GL_BACK_LEFT;
if (fbo != 0)
obj = GL_COLOR_ATTACHMENT0;
GLint type = 0;
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, obj,
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, obj,
GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE, &type);
switch (type) {
case GL_FLOAT: fmt->type = PL_FMT_FLOAT; break;
......@@ -518,16 +520,16 @@ static bool gl_fb_query(const struct pl_gpu *gpu, int fbo, struct pl_fmt *fmt)
default: fmt->type = PL_FMT_UNKNOWN; break;
}
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, obj,
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, obj,
GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE, &fmt->component_depth[0]);
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, obj,
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, obj,
GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE, &fmt->component_depth[1]);
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, obj,
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, obj,
GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE, &fmt->component_depth[2]);
glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, obj,
glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER, obj,
GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE, &fmt->component_depth[3]);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
int bits = 0;
for (int i = 0; i < 4; i++)
......@@ -720,22 +722,22 @@ const struct pl_tex *pl_opengl_wrap(const struct pl_gpu *gpu,
if (can_fbo) {
glGenFramebuffers(1, &tex_gl->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex_gl->fbo);
switch (dims) {
case 1:
glFramebufferTexture1D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
tex_gl->target, tex_gl->texture, 0);
break;
case 2:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
tex_gl->target, tex_gl->texture, 0);
break;
case 3: abort();
}
GLenum err = glCheckFramebufferStatus(GL_FRAMEBUFFER);
GLenum err = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
if (err != GL_FRAMEBUFFER_COMPLETE) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
PL_ERR(gpu, "Failed creating framebuffer: error code %d", err);
goto error;
}
......@@ -756,7 +758,7 @@ const struct pl_tex *pl_opengl_wrap(const struct pl_gpu *gpu,
tex->params.host_readable = true;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
if (!gl_check_err(gpu, "pl_opengl_wrap: fbo"))
goto error;
}
......@@ -794,15 +796,20 @@ static void gl_tex_invalidate(const struct pl_gpu *gpu, const struct pl_tex *tex
struct pl_gl *p = TA_PRIV(gpu);
struct pl_tex_gl *tex_gl = TA_PRIV(tex);
if (!p->has_invalidate)
if (!p->has_invalidate_fb)
return;
if (tex_gl->wrapped_fb) {
glBindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, (GLenum[]){GL_COLOR});
glBindFramebuffer(GL_FRAMEBUFFER, 0);
} else {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex_gl->fbo);
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, (GLenum[]){GL_COLOR});
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
} else if (p->has_invalidate_tex) {
glInvalidateTexImage(tex_gl->texture, 0);
} else {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex_gl->fbo);
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER,
1, (GLenum[]){GL_COLOR_ATTACHMENT0});
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
gl_check_err(gpu, "gl_tex_invalidate");
......@@ -814,10 +821,10 @@ static void gl_tex_clear(const struct pl_gpu *gpu, const struct pl_tex *tex,
struct pl_tex_gl *tex_gl = TA_PRIV(tex);
pl_assert(tex_gl->fbo || tex_gl->wrapped_fb);
glBindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tex_gl->fbo);
glClearColor(color[0], color[1], color[2], color[3]);
glClear(GL_COLOR_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
gl_check_err(gpu, "gl_tex_clear");
}
......@@ -1151,12 +1158,12 @@ static bool gl_tex_download(const struct pl_gpu *gpu,
// No 3D framebuffers
pl_assert(pl_rect_d(params->rc) == 1);
glBindFramebuffer(GL_FRAMEBUFFER, tex_gl->fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, tex_gl->fbo);
for (int y = params->rc.y0; y < params->rc.y1; y += rows) {
glReadPixels(params->rc.x0, y, pl_rect_w(params->rc), rows,
tex_gl->format, tex_gl->type, dst);
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glPixelStorei(GL_PACK_ALIGNMENT, 4);
if (p->has_stride)
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
......@@ -1188,9 +1195,9 @@ static int gl_desc_namespace(const struct pl_gpu *gpu, enum pl_desc_type type)
return (int) type;
}
#define GL_CACHE_MAGIC {'P','L','G','L'}
#define GL_CACHE_VERSION 1
static const char gl_cache_magic[4] = GL_CACHE_MAGIC;
#define CACHE_MAGIC {'P','L','G','L'}
#define CACHE_VERSION 1
static const char gl_cache_magic[4] = CACHE_MAGIC;
struct gl_cache_header {
char magic[sizeof(gl_cache_magic)];
......@@ -1217,7 +1224,7 @@ static GLuint load_cached_program(const struct pl_gpu *gpu,
if (strncmp(header->magic, gl_cache_magic, sizeof(gl_cache_magic)) != 0)
return 0;
if (header->cache_version != GL_CACHE_VERSION)
if (header->cache_version != CACHE_VERSION)
return 0;
GLuint prog = glCreateProgram();
......@@ -1406,8 +1413,8 @@ static const struct pl_pass *gl_pass_create(const struct pl_gpu *gpu,
uint8_t *buffer = talloc_size(NULL, size);
GLsizei actual_size = 0;
struct gl_cache_header header = {
.magic = GL_CACHE_MAGIC,
.cache_version = GL_CACHE_VERSION,
.magic = CACHE_MAGIC,
.cache_version = CACHE_VERSION,
};
glGetProgramBinary(pass_gl->program, size, &actual_size,
......@@ -1646,10 +1653,10 @@ static void gl_pass_run(const struct pl_gpu *gpu,
switch (pass->params.type) {
case PL_PASS_RASTER: {
struct pl_tex_gl *target_gl = TA_PRIV(params->target);
glBindFramebuffer(GL_FRAMEBUFFER, target_gl->fbo);
if (!pass->params.load_target && p->has_invalidate) {
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target_gl->fbo);
if (!pass->params.load_target && p->has_invalidate_fb) {
GLenum fb = target_gl->fbo ? GL_COLOR_ATTACHMENT0 : GL_COLOR;
glInvalidateFramebuffer(GL_FRAMEBUFFER, 1, &fb);
glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &fb);
}
glViewport(params->viewport.x0, params->viewport.y0,
......@@ -1710,7 +1717,7 @@ static void gl_pass_run(const struct pl_gpu *gpu,
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDisable(GL_SCISSOR_TEST);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
break;
}
......
......@@ -512,8 +512,8 @@ fallback:
static void draw_overlays(struct pass_state *pass, const struct pl_tex *fbo,
const struct pl_overlay *overlays, int num,
struct pl_color_space color, bool use_sigmoid,
struct pl_transform2x2 *scale,
struct pl_color_space color, struct pl_color_repr repr,
bool use_sigmoid, struct pl_transform2x2 *scale,
const struct pl_render_params *params)
{
struct pl_renderer *rr = pass->rr;
......@@ -589,14 +589,16 @@ static void draw_overlays(struct pass_state *pass, const struct pl_tex *fbo,
default: abort();
}
struct pl_color_repr repr = ol->repr;
pl_shader_decode_color(sh, &repr, NULL);
struct pl_color_repr ol_repr = ol->repr;
pl_shader_decode_color(sh, &ol_repr, NULL);
pl_shader_color_map(sh, params->color_map_params, ol->color, color,
NULL, false);
if (use_sigmoid)
pl_shader_sigmoidize(sh, params->sigmoid_params);
pl_shader_encode_color(sh, &repr);
static const struct pl_blend_params blend_params = {
.src_rgb = PL_BLEND_SRC_ALPHA,
.dst_rgb = PL_BLEND_ONE_MINUS_SRC_ALPHA,
......@@ -1401,7 +1403,7 @@ static bool pass_scale_main(struct pl_renderer *rr, struct pass_state *pass,
}
draw_overlays(pass, img->tex, image->overlays, image->num_overlays,
img->color, use_sigmoid, &tf, params);
img->color, img->repr, use_sigmoid, &tf, params);
pass_hook(pass, img, PL_HOOK_PRE_KERNEL, params);
......@@ -1727,12 +1729,12 @@ bool pl_render_image(struct pl_renderer *rr, const struct pl_image *pimage,
};
draw_overlays(&pass, target->fbo, image->overlays, image->num_overlays,
target->color, false, &scale, params);
target->color, target->repr, false, &scale, params);
}
// Draw the final output overlays
draw_overlays(&pass, target->fbo, target->overlays, target->num_overlays,
target->color, false, NULL, params);
target->color, target->repr, false, NULL, params);
talloc_free(pass.tmp);
return true;
......
......@@ -603,6 +603,30 @@ bool pl_needs_av1_grain(const struct pl_av1_grain_params *params)
return false;
}
static inline bool av1_grain_data_eq(const struct pl_av1_grain_data *a,
const struct pl_av1_grain_data *b)
{
// Could skip some checks for fields that will end up unused, but I decided
// it's not worth the effort to re-implement the full logic here
return a->grain_seed == b->grain_seed &&
a->num_points_y == b->num_points_y &&
a->chroma_scaling_from_luma == b->chroma_scaling_from_luma &&
a->scaling_shift == b->scaling_shift &&
a->ar_coeff_lag == b->ar_coeff_lag &&
a->ar_coeff_shift == b->ar_coeff_shift &&
a->grain_scale_shift == b->grain_scale_shift &&
a->overlap == b->overlap &&
!memcmp(a->points_y, b->points_y, sizeof(a->points_y)) &&
!memcmp(a->num_points_uv, b->num_points_uv, sizeof(a->num_points_uv)) &&
!memcmp(a->points_uv, b->points_uv, sizeof(a->points_uv)) &&
!memcmp(a->ar_coeffs_y, b->ar_coeffs_y, sizeof(a->ar_coeffs_y)) &&
!memcmp(a->ar_coeffs_uv, b->ar_coeffs_uv, sizeof(a->ar_coeffs_uv)) &&
!memcmp(a->uv_mult, b->uv_mult, sizeof(a->uv_mult)) &&
!memcmp(a->uv_mult_luma, b->uv_mult_luma, sizeof(a->uv_mult_luma)) &&
!memcmp(a->uv_offset, b->uv_offset, sizeof(a->uv_offset));
}
bool pl_shader_av1_grain(struct pl_shader *sh,
struct pl_shader_obj **grain_state,
const struct pl_av1_grain_params *params)
......@@ -680,7 +704,7 @@ bool pl_shader_av1_grain(struct pl_shader *sh,
// only related to chroma and skip updating for changes to irrelevant
// parts, but this is probably not worth it since the grain_seed is
// expected to change per frame anyway.
bool needs_update = memcmp(data, &obj->data, sizeof(*data)) != 0 ||
bool needs_update = !av1_grain_data_eq(data, &obj->data) ||
!pl_color_repr_equal(params->repr, &obj->repr) ||
offsets_x != obj->offsets_x ||
offsets_y != obj->offsets_y ||
......
......@@ -823,9 +823,11 @@ static void pl_shader_tone_map(struct pl_shader *sh, struct pl_color_space src,
dst_range, dst_range);
}
// Rename `color.rgb` to something shorter for conciseness
GLSL("vec3 sig = color.rgb; \n"
"vec3 sig_orig = sig; \n");
// Rename `color.rgb` to something shorter for conciseness, and also
// apply clipping to prevent the tone mapping functions from exploding
// for input values exceeding sig_peak
GLSL("vec3 sig = min(color.rgb, sig_peak); \n"
"vec3 sig_orig = color.rgb; \n");
// Scale the signal to compensate for differences in the average brightness
GLSL("float slope = min(%f, %f / sig_avg); \n"
......@@ -836,7 +838,7 @@ static void pl_shader_tone_map(struct pl_shader *sh, struct pl_color_space src,
float param = params->tone_mapping_param;
switch (params->tone_mapping_algo) {
case PL_TONE_MAPPING_CLIP:
GLSL("sig *= %f;\n", PL_DEF(param, 1.0));
GLSL("sig *= min(%f, 1.0) ;\n", PL_DEF(param, 1.0));
break;
case PL_TONE_MAPPING_MOBIUS:
......@@ -892,7 +894,7 @@ static void pl_shader_tone_map(struct pl_shader *sh, struct pl_color_space src,
break;
case PL_TONE_MAPPING_LINEAR:
GLSL("sig *= %f / sig_peak;\n", PL_DEF(param, 1.0));
GLSL("sig *= min(%f / sig_peak, 1.0);\n", PL_DEF(param, 1.0));
break;
case PL_TONE_MAPPING_BT_2390:
......@@ -934,8 +936,7 @@ static void pl_shader_tone_map(struct pl_shader *sh, struct pl_color_space src,
abort();
}
GLSL("sig = min(sig, 1.01); \n"
"vec3 sig_lin = sig_orig * (sig[sig_idx] / sig_orig[sig_idx]); \n");
GLSL("vec3 sig_lin = sig_orig * (sig[sig_idx] / sig_orig[sig_idx]); \n");
// Mix between the per-channel tone mapped `sig` and the linear tone
// mapped `sig_lin` based on the desaturation strength
......
......@@ -382,6 +382,7 @@ bool pl_shader_sample_polar(struct pl_shader *sh,
pl_assert(gpu);
bool has_compute = gpu->caps & PL_GPU_CAP_COMPUTE && !params->no_compute;
has_compute &= sh_glsl(sh).version >= 130; // needed for round()
if (!src->tex && has_compute) {
// FIXME: Could maybe solve this by communicating the wbase from
// invocation 0 to the rest of the workgroup using shmem, which would
......
......@@ -32,6 +32,9 @@ static const struct spirv_compiler_fns *compilers[] = {
struct spirv_compiler *spirv_compiler_create(struct pl_context *ctx,
uint32_t api_version)
{
// Strip the patch version
api_version &= ~0xfff;
for (int i = 0; i < PL_ARRAY_SIZE(compilers); i++) {
const struct spirv_compiler_fns *impl = compilers[i];
pl_info(ctx, "Initializing SPIR-V compiler '%s'", impl->name);
......
......@@ -24,7 +24,6 @@ const struct pl_vk_inst_params pl_vk_inst_default_params = {0};
struct vk_fun {
const char *name;
const char *alias;
size_t offset;
bool device_level;
};
......@@ -46,13 +45,6 @@ struct vk_ext {
.device_level = true, \
}
#define VK_DEV_FUN_ALIAS(N, ALIAS) \
{ .name = "vk" #N, \
.alias = #ALIAS, \
.offset = offsetof(struct vk_ctx, N), \
.device_level = true, \
}
// Table of optional vulkan instance extensions
static const char *vk_instance_extensions[] = {
VK_KHR_SURFACE_EXTENSION_NAME,
......@@ -168,7 +160,7 @@ static const struct vk_ext vk_device_extensions[] = {
.name = VK_EXT_HOST_QUERY_RESET_EXTENSION_NAME,
.core_ver = VK_API_VERSION_1_2,
.funs = (struct vk_fun[]) {
VK_DEV_FUN_ALIAS(ResetQueryPoolEXT, vkResetQueryPool),
VK_DEV_FUN(ResetQueryPoolEXT),
{0},
},
},
......@@ -308,6 +300,40 @@ static const struct vk_fun vk_dev_funs[] = {
VK_DEV_FUN(WaitForFences),
};
static void load_vk_fun(struct vk_ctx *vk, const struct vk_fun *fun)
{
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
if (fun->device_level) {
*pfn = vk->GetDeviceProcAddr(vk->dev, fun->name);
} else {
*pfn = vk->GetInstanceProcAddr(vk->inst, fun->name);
};
if (!*pfn) {
// Some functions get their extension suffix stripped when promoted
// to core. As a very simple work-around to this, try loading the
// function a second time with the reserved suffixes stripped.
static const char *ext_suffixes[] = { "KHR", "EXT" };
struct bstr fun_name = bstr0(fun->name);
char buf[64];
for (int i = 0; i < PL_ARRAY_SIZE(ext_suffixes); i++) {
if (!bstr_eatend(&fun_name, bstr0(ext_suffixes[i])))
continue;
pl_assert(sizeof(buf) > fun_name.len);
snprintf(buf, sizeof(buf), "%.*s", BSTR_P(fun_name));
if (fun->device_level) {
*pfn = vk->GetDeviceProcAddr(vk->dev, buf);
} else {
*pfn = vk->GetInstanceProcAddr(vk->inst, buf);
}
return;
}
}
}
// Private struct for pl_vk_inst
struct priv {
VkDebugReportCallbackEXT debug_report_cb;
......@@ -375,7 +401,7 @@ static VkBool32 VKAPI_PTR vk_dbg_utils_cb(VkDebugUtilsMessageSeverityFlagBitsEXT
for (int i = 0; i < data->objectCount; i++) {
const VkDebugUtilsObjectNameInfoEXT *obj = &data->pObjects[i];
pl_msg(ctx, lev, " using %s: %s (0x%llx)",
vk_obj_str(obj->objectType),
vk_obj_type(obj->objectType),
obj->pObjectName ? obj->pObjectName : "anon",
(unsigned long long) obj->objectHandle);
}
......@@ -417,7 +443,7 @@ static VkBool32 VKAPI_PTR vk_dbg_report_cb(VkDebugReportFlagsEXT flags,
// Note: We can freely cast VkDebugReportObjectTypeEXT to VkObjectType
pl_msg(ctx, lev, "vk [%s] %d: %s (obj 0x%llx (%s), loc 0x%zx)",
layer, (int) msgCode, msg, (unsigned long long) obj,
vk_obj_str((VkObjectType) objType), loc);
vk_obj_type((VkObjectType) objType), loc);
return !!(flags & VK_DEBUG_REPORT_ERROR_BIT_EXT);
}
......@@ -1171,25 +1197,12 @@ static bool device_init(struct vk_ctx *vk, const struct pl_vulkan_params *params
VK(vk->CreateDevice(vk->physd, &dinfo, VK_ALLOC, &vk->dev));
// Load all mandatory device-level functions
for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++) {
const struct vk_fun *fun = &vk_dev_funs[i];
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
pl_assert(fun->device_level);
*pfn = vk->GetDeviceProcAddr(vk->dev, fun->name);
}
for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++)
load_vk_fun(vk, &vk_dev_funs[i]);
// Load all of the optional functions from the extensions we enabled
for (int i = 0; i < num_ext_funs; i++) {
const struct vk_fun *fun = ext_funs[i];
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
if (fun->device_level) {
*pfn = vk->GetDeviceProcAddr(vk->dev, fun->name);
if (fun->alias && !*pfn)
*pfn = vk->GetDeviceProcAddr(vk->dev, fun->alias);
} else {
*pfn = vk->GetInstanceProcAddr(vk->inst, fun->name);
};
}
for (int i = 0; i < num_ext_funs; i++)
load_vk_fun(vk, ext_funs[i]);
// Create the command pools
for (int i = 0; i < num_qinfos; i++) {
......@@ -1261,12 +1274,8 @@ const struct pl_vulkan *pl_vulkan_create(struct pl_context *ctx,
// Directly load all mandatory instance-level function pointers, since
// these will be required for all further device creation logic
for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++) {
const struct vk_fun *fun = &vk_inst_funs[i];
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
pl_assert(!fun->device_level);
*pfn = vk->GetInstanceProcAddr(vk->inst, fun->name);
}
for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++)
load_vk_fun(vk, &vk_inst_funs[i]);
// Choose the physical device
if (params->device) {
......@@ -1394,11 +1403,14 @@ const struct pl_vulkan *pl_vulkan_import(struct pl_context *ctx,
if (!vk->GetInstanceProcAddr)
goto error;
for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++) {
const struct vk_fun *fun = &vk_inst_funs[i];
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
pl_assert(!fun->device_level);
*pfn = vk->GetInstanceProcAddr(vk->inst, fun->name);
for (int i = 0; i < PL_ARRAY_SIZE(vk_inst_funs); i++)
load_vk_fun(vk, &vk_inst_funs[i]);
if (!vk->GetPhysicalDeviceProperties2KHR) {
PL_FATAL(vk, "Provided VkInstance does not support "
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
", cannot continue!");
goto error;
}
VkPhysicalDeviceIDPropertiesKHR id_props = {
......@@ -1434,12 +1446,8 @@ const struct pl_vulkan *pl_vulkan_import(struct pl_context *ctx,
vk->features = *features;
// Load all mandatory device-level functions
for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++) {
const struct vk_fun *fun = &vk_dev_funs[i];
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) fun->offset);
pl_assert(fun->device_level);
*pfn = vk->GetDeviceProcAddr(vk->dev, fun->name);
}
for (int i = 0; i < PL_ARRAY_SIZE(vk_dev_funs); i++)
load_vk_fun(vk, &vk_dev_funs[i]);
// Load all of the optional functions from the extensions enabled
for (int i = 0; i < PL_ARRAY_SIZE(vk_device_extensions); i++) {
......@@ -1449,14 +1457,8 @@ const struct pl_vulkan *pl_vulkan_import(struct pl_context *ctx,
(ext->core_ver && ext->core_ver >= vk->api_ver))
{
// Extension is available, directly load it
for (const struct vk_fun *f = ext->funs; f->name; f++) {
PFN_vkVoidFunction *pfn = (void *) ((uintptr_t) vk + (ptrdiff_t) f->offset);
if (f->device_level) {
*pfn = vk->GetDeviceProcAddr(vk->dev, f->name);
} else {
*pfn = vk->GetInstanceProcAddr(vk->inst, f->name);
};
}
for (const struct vk_fun *f = ext->funs; f->name; f++)
load_vk_fun(vk, f);
break;
}
}
......
......@@ -1167,7 +1167,7 @@ const struct pl_tex *pl_vulkan_wrap(const struct pl_gpu *gpu,
if (!format) {
PL_ERR(gpu, "Could not find pl_fmt suitable for wrapped image "
"with VkFormat 0x%x", (unsigned) params->format);
"with format %s", vk_fmt_name(params->format));
goto error;
}
......@@ -2106,9 +2106,9 @@ static const VkDescriptorType dsType[] = {
[PL_DESC_BUF_TEXEL_STORAGE] = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
};
#define VK_CACHE_MAGIC {'R','A','V','K'}
#define VK_CACHE_VERSION 2
static const char vk_cache_magic[4] = VK_CACHE_MAGIC;
#define CACHE_MAGIC {'R','A','V','K'}
#define CACHE_VERSION 2
static const char vk_cache_magic[4] = CACHE_MAGIC;
struct vk_cache_header {
char magic[sizeof(vk_cache_magic)];
......@@ -2141,7 +2141,7 @@ static bool vk_use_cached_program(const struct pl_pass_params *params,
if (strncmp(header->magic, vk_cache_magic, sizeof(vk_cache_magic)) != 0)
return false;
if (header->cache_version != VK_CACHE_VERSION)
if (header->cache_version != CACHE_VERSION)
return false;
if (strncmp(header->compiler, spirv->name, sizeof(header->compiler)) != 0)
return false;
......@@ -2538,8 +2538,8 @@ no_descriptors: ;
VK(vk->GetPipelineCacheData(vk->dev, pipeCache, &cache.len, cache.start));
struct vk_cache_header header = {
.magic = VK_CACHE_MAGIC,
.cache_version = VK_CACHE_VERSION,
.magic = CACHE_MAGIC,
.cache_version = CACHE_VERSION,
.compiler_version = p->spirv->compiler_version,
.vert_spirv_len = vert.len,
.frag_spirv_len = frag.len,
......
......@@ -154,8 +154,8 @@ static bool pick_surf_format(const struct pl_gpu *gpu, const struct vk_ctx *vk,
if (vk_map_color_space(out_format->colorSpace, space)) {
return true;
} else {
PL_ERR(gpu, "User-supplied surface format unsupported: 0x%x",
(unsigned int) out_format->format);
PL_ERR(gpu, "User-supplied surface format unsupported: %s",
vk_fmt_name(out_format->format));
}
}
......@@ -165,8 +165,9 @@ static bool pick_surf_format(const struct pl_gpu *gpu, const struct vk_ctx *vk,
PL_DEBUG(gpu, "Available surface formats:");
for (int i = 0; i < num; i++) {
PL_DEBUG(gpu, " %d: format: 0x%x, space: 0x%x", i,
formats[i].format, formats[i].colorSpace);
PL_DEBUG(gpu, " %d: format: %s, space: %s", i,
vk_fmt_name(formats[i].format),
vk_csp_name(formats[i].colorSpace));
}
for (int i = 0; i < num; i++) {
......@@ -264,8 +265,8 @@ const struct pl_swapchain *pl_vulkan_create_swapchain(const struct pl_vulkan *pl
if (!pick_surf_format(gpu, vk, params->surface, &sfmt, &csp))
return NULL;
PL_DEBUG(gpu, "Picked surface format 0x%x, space 0x%x",
sfmt.format, sfmt.colorSpace);
PL_DEBUG(gpu, "Picked surface format %s, space %s",
vk_fmt_name(sfmt.format), vk_csp_name(sfmt.colorSpace));
struct pl_swapchain *sw = talloc_zero_priv(NULL, struct pl_swapchain, struct priv);
sw->impl = &vulkan_swapchain;
......@@ -379,8 +380,8 @@ static bool update_swapchain_info(struct priv *p, VkSwapchainCreateInfoKHR *info
if (caps.supportedCompositeAlpha & alphaModes[i].vk_mode) {
info->compositeAlpha = alphaModes[i].vk_mode;
p->color_repr.alpha = alphaModes[i].pl_mode;
PL_DEBUG(vk, "Requested alpha compositing mode: 0x%x",
info->compositeAlpha);
PL_DEBUG(vk, "Requested alpha compositing mode: %s",
vk_alpha_mode(info->compositeAlpha));
break;
}
}
......@@ -402,7 +403,8 @@ static bool update_swapchain_info(struct priv *p, VkSwapchainCreateInfoKHR *info
for (int i = 0; i < PL_ARRAY_SIZE(rotModes); i++) {
if (caps.supportedTransforms & rotModes[i]) {
info->preTransform = rotModes[i];
PL_DEBUG(vk, "Requested surface transform: 0x%x", info->preTransform);
PL_DEBUG(vk, "Requested surface transform: %s",
vk_surface_transform(info->preTransform));
break;
}
}
......
......@@ -21,7 +21,11 @@
// Return a human-readable name for various vulkan enums
const char *vk_res_str(VkResult res);
const char *vk_obj_str(VkObjectType obj);
const char *vk_fmt_name(VkFormat fmt);
const char *vk_csp_name(VkColorSpaceKHR csp);
const char *vk_obj_type(VkObjectType obj);
const char *vk_alpha_mode(VkCompositeAlphaFlagsKHR alpha);
const char *vk_surface_transform(VkSurfaceTransformFlagsKHR transform);
// Return the size of an arbitrary vulkan struct. Returns 0 for unknown structs
size_t vk_struct_size(VkStructureType stype);
......
......@@ -41,7 +41,52 @@ const char *vk_res_str(VkResult res)
}
}
const char *vk_obj_str(VkObjectType obj)
const char *vk_fmt_name(VkFormat fmt)
{
switch (fmt) {
%for fmt in vkformats:
case ${fmt}: return "${fmt}";
%endfor
default: return "unknown format";
}
}
const char *vk_csp_name(VkColorSpaceKHR csp)
{
switch (csp) {
%for csp in vkspaces:
case ${csp}: return "${csp}";
%endfor
default: return "unknown color space";
}
}
const char *vk_alpha_mode(VkCompositeAlphaFlagsKHR alpha)
{
switch (alpha) {
%for mode in vkalphas:
case ${mode}: return "${mode}";
%endfor
default: return "unknown alpha mode";
}
}
const char *vk_surface_transform(VkSurfaceTransformFlagsKHR tf)
{
switch (tf) {
%for tf in vktransforms:
case ${tf}: return "${tf}";
%endfor
default: return "unknown surface transform";
}
}
const char *vk_obj_type(VkObjectType obj)
{
switch (obj) {
%for obj in vkobjects:
......@@ -68,18 +113,28 @@ class Obj(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def get_vkresults(registry):
for e in registry.findall('enums[@name="VkResult"]/enum'):
def findall_enum(registry, name):
for e in registry.iterfind('enums[@name="{0}"]/enum'.format(name)):
if not 'alias' in e.attrib:
yield e
for e in registry.iterfind('.//enum[@extends="{0}"]'.format(name)):
# ext 289 is a non-existing extension that defines some names for
# proprietary downstream consumers, causes problems unless excluded
if not 'alias' in e.attrib and e.attrib.get('extnumber', '0') != '289':
yield e
def get_vkenum(registry, enum):
for e in findall_enum(registry, enum):
yield e.attrib['name']
def get_vkobjects(registry):
for e in registry.findall('enums[@name="VkObjectType"]/enum'):
for e in findall_enum(registry, 'VkObjectType'):
if 'comment' in e.attrib:
yield Obj(enum = e.attrib['name'],
name = e.attrib['comment'])
def get_vkstructs(registry):
for e in registry.findall('types/type[@category="struct"]'):
for e in registry.iterfind('types/type[@category="struct"]'):
# Strings for platform-specific crap we want to blacklist as they will
# most likely cause build failures
blacklist_strs = [
......@@ -90,7 +145,7 @@ def get_vkstructs(registry):
continue
stype = None
for m in e.findall('member'):
for m in e.iterfind('member'):
if m.find('name').text == 'sType':
stype = m
break
......@@ -128,7 +183,11 @@ if __name__ == '__main__':
registry = ET.parse(xmlfile)
with open(outfile, 'w') as f:
f.write(TEMPLATE.render(
vkresults = get_vkresults(registry),
vkresults = get_vkenum(registry, 'VkResult'),
vkformats = get_vkenum(registry, 'VkFormat'),
vkspaces = get_vkenum(registry, 'VkColorSpaceKHR'),
vkalphas = get_vkenum(registry, 'VkCompositeAlphaFlagBitsKHR'),
vktransforms = get_vkenum(registry, 'VkSurfaceTransformFlagBitsKHR'),
vkobjects = get_vkobjects(registry),
vkstructs = get_vkstructs(registry),
))