improve BlobCache API and compatibility

- the insert and retrieve handlers can now be set/unset independently.
  this could be useful for debugging.

- program caching is disabled if the GL implementation doesn't support it.

- removed unused code

FIXES=[307549547]
This commit is contained in:
Mathias Agopian
2023-10-25 11:19:57 -07:00
committed by Mathias Agopian
parent 73b0751ccf
commit f0d5cd3fa1
8 changed files with 108 additions and 85 deletions

View File

@@ -114,6 +114,7 @@ public:
* Platform. The <insert> and <retrieve> Invocables may be called at any time and
* from any thread from the time at which setBlobFunc is called until the time that Platform
* is destroyed. Concurrent calls to these functions from different threads is also allowed.
* Either function can be null.
*
* @param insertBlob an Invocable that inserts a new value into the cache and associates
* it with the given key
@@ -123,9 +124,21 @@ public:
void setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept;
/**
* @return true if setBlobFunc was called.
* @return true if insertBlob is valid.
*/
bool hasBlobFunc() const noexcept;
bool hasInsertBlobFunc() const noexcept;
/**
* @return true if retrieveBlob is valid.
*/
bool hasRetrieveBlobFunc() const noexcept;
/**
* @return true if either of insertBlob or retrieveBlob are valid.
*/
bool hasBlobFunc() const noexcept {
return hasInsertBlobFunc() || hasRetrieveBlobFunc();
}
/**
* To insert a new binary value into the cache and associate it with a given

View File

@@ -28,14 +28,16 @@ bool Platform::pumpEvents() noexcept {
}
void Platform::setBlobFunc(InsertBlobFunc&& insertBlob, RetrieveBlobFunc&& retrieveBlob) noexcept {
if (!mInsertBlob && !mRetrieveBlob) {
mInsertBlob = std::move(insertBlob);
mRetrieveBlob = std::move(retrieveBlob);
}
mInsertBlob = std::move(insertBlob);
mRetrieveBlob = std::move(retrieveBlob);
}
bool Platform::hasBlobFunc() const noexcept {
return mInsertBlob && mRetrieveBlob;
bool Platform::hasInsertBlobFunc() const noexcept {
return bool(mInsertBlob);
}
bool Platform::hasRetrieveBlobFunc() const noexcept {
return bool(mRetrieveBlob);
}
void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {

View File

@@ -16,6 +16,8 @@
#include "OpenGLBlobCache.h"
#include "OpenGLContext.h"
#include <backend/Platform.h>
#include <backend/Program.h>
@@ -28,17 +30,18 @@ struct OpenGLBlobCache::Blob {
char data[];
};
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
Program const& program) noexcept {
SYSTRACE_CALL();
OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
: mCachingSupported(gl.gets.num_program_binary_formats >= 1) {
}
if (!platform.hasBlobFunc()) {
GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
Program const& program) const noexcept {
SYSTRACE_CALL();
if (!mCachingSupported || !platform.hasRetrieveBlobFunc()) {
// the key is never updated in that case
return 0;
}
SYSTRACE_CONTEXT();
GLuint programId = 0;
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
@@ -64,8 +67,10 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
programId = glCreateProgram();
SYSTRACE_NAME("glProgramBinary");
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
{ // scope for systrace
SYSTRACE_NAME("glProgramBinary");
glProgramBinary(programId, blob->format, blob->data, programBinarySize);
}
if (UTILS_UNLIKELY(glGetError() != GL_NO_ERROR)) {
// glProgramBinary can fail if for instance the driver has been updated
@@ -85,46 +90,36 @@ GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
void OpenGLBlobCache::insert(Platform& platform,
BlobCacheKey const& key, GLuint program) noexcept {
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
SYSTRACE_CALL();
if (platform.hasBlobFunc()) {
SYSTRACE_CONTEXT();
GLenum format;
GLint programBinarySize = 0;
if (!mCachingSupported || !platform.hasInsertBlobFunc()) {
// the key is never updated in that case
return;
}
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
GLenum format;
GLint programBinarySize = 0;
{ // scope for systrace
SYSTRACE_NAME("glGetProgramiv");
glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH, &programBinarySize);
if (programBinarySize) {
size_t const size = sizeof(Blob) + programBinarySize;
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
if (UTILS_LIKELY(blob)) {
}
if (programBinarySize) {
size_t const size = sizeof(Blob) + programBinarySize;
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
if (UTILS_LIKELY(blob)) {
{ // scope for systrace
SYSTRACE_NAME("glGetProgramBinary");
glGetProgramBinary(program, programBinarySize, &programBinarySize, &format,
blob->data);
GLenum const error = glGetError();
if (error == GL_NO_ERROR) {
blob->format = format;
platform.insertBlob(key.data(), key.size(), blob.get(), size);
}
glGetProgramBinary(program, programBinarySize,
&programBinarySize, &format, blob->data);
}
GLenum const error = glGetError();
if (error == GL_NO_ERROR) {
blob->format = format;
platform.insertBlob(key.data(), key.size(), blob.get(), size);
}
}
}
#endif
}
void OpenGLBlobCache::insert(Platform& platform, BlobCacheKey const& key,
GLenum format, void* data, GLsizei programBinarySize) noexcept {
SYSTRACE_CALL();
if (platform.hasBlobFunc()) {
if (programBinarySize) {
size_t const size = sizeof(Blob) + programBinarySize;
std::unique_ptr<Blob, decltype(&::free)> blob{ (Blob*)malloc(size), &::free };
if (UTILS_LIKELY(blob)) {
blob->format = format;
memcpy(blob->data, data, programBinarySize);
platform.insertBlob(key.data(), key.size(), blob.get(), size);
}
}
}
}
} // namespace filament::backend

View File

@@ -25,20 +25,21 @@ namespace filament::backend {
class Platform;
class Program;
class OpenGLContext;
class OpenGLBlobCache {
public:
static GLuint retrieve(BlobCacheKey* key, Platform& platform,
Program const& program) noexcept;
explicit OpenGLBlobCache(OpenGLContext& gl) noexcept;
static void insert(Platform& platform,
GLuint retrieve(BlobCacheKey* key, Platform& platform,
Program const& program) const noexcept;
void insert(Platform& platform,
BlobCacheKey const& key, GLuint program) noexcept;
static void insert(Platform& platform, BlobCacheKey const& key,
GLenum format, void* data, GLsizei programBinarySize) noexcept;
private:
struct Blob;
bool mCachingSupported = false;
};
} // namespace filament::backend

View File

@@ -99,38 +99,41 @@ OpenGLContext::OpenGLContext() noexcept {
if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
&gets.max_uniform_block_size);
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
&gets.max_uniform_buffer_bindings);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
&gets.uniform_buffer_offset_alignment);
glGetIntegerv(GL_MAX_SAMPLES,
&gets.max_samples);
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
&gets.max_draw_buffers);
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&gets.max_transform_feedback_separate_attribs);
#ifdef GL_EXT_texture_filter_anisotropic
if (ext.EXT_texture_filter_anisotropic) {
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &gets.max_anisotropy);
}
#endif
glGetIntegerv(GL_MAX_DRAW_BUFFERS,
&gets.max_draw_buffers);
glGetIntegerv(GL_MAX_SAMPLES,
&gets.max_samples);
glGetIntegerv(GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
&gets.max_transform_feedback_separate_attribs);
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE,
&gets.max_uniform_block_size);
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS,
&gets.max_uniform_buffer_bindings);
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS,
&gets.num_program_binary_formats);
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT,
&gets.uniform_buffer_offset_alignment);
#endif
}
#ifdef BACKEND_OPENGL_VERSION_GLES
else {
gets.max_anisotropy = 1;
gets.max_draw_buffers = 1;
gets.max_samples = 1;
gets.max_transform_feedback_separate_attribs = 0;
gets.max_uniform_block_size = 0;
gets.max_uniform_buffer_bindings = 0;
gets.num_program_binary_formats = 0;
gets.uniform_buffer_offset_alignment = 0;
gets.max_samples = 1;
gets.max_draw_buffers = 1;
gets.max_transform_feedback_separate_attribs = 0;
gets.max_anisotropy = 1;
}
#endif
slog.v << "Feature level: " << +mFeatureLevel << '\n';
slog.v << "Active workarounds: " << '\n';
UTILS_NOUNROLL
@@ -143,13 +146,18 @@ OpenGLContext::OpenGLContext() noexcept {
#ifndef NDEBUG
// this is useful for development
slog.v << "GL_MAX_DRAW_BUFFERS = " << gets.max_draw_buffers << '\n'
<< "GL_MAX_RENDERBUFFER_SIZE = " << gets.max_renderbuffer_size << '\n'
<< "GL_MAX_SAMPLES = " << gets.max_samples << '\n'
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT = " << gets.max_anisotropy << '\n'
<< "GL_MAX_UNIFORM_BLOCK_SIZE = " << gets.max_uniform_block_size << '\n'
<< "GL_MAX_TEXTURE_IMAGE_UNITS = " << gets.max_texture_image_units << '\n'
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT = " << gets.uniform_buffer_offset_alignment << '\n'
slog.v
<< "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" << gets.max_anisotropy << '\n'
<< "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS" << gets.max_combined_texture_image_units << '\n'
<< "GL_MAX_DRAW_BUFFERS" << gets.max_draw_buffers << '\n'
<< "GL_MAX_RENDERBUFFER_SIZE" << gets.max_renderbuffer_size << '\n'
<< "GL_MAX_SAMPLES" << gets.max_samples << '\n'
<< "GL_MAX_TEXTURE_IMAGE_UNITS" << gets.max_texture_image_units << '\n'
<< "GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS" << gets.max_transform_feedback_separate_attribs << '\n'
<< "GL_MAX_UNIFORM_BLOCK_SIZE" << gets.max_uniform_block_size << '\n'
<< "GL_MAX_UNIFORM_BUFFER_BINDINGS" << gets.max_uniform_buffer_bindings << '\n'
<< "GL_NUM_PROGRAM_BINARY_FORMATS" << gets.num_program_binary_formats << '\n'
<< "GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT" << gets.uniform_buffer_offset_alignment << '\n'
;
flush(slog.v);
#endif

View File

@@ -153,14 +153,15 @@ public:
// glGet*() values
struct Gets {
GLfloat max_anisotropy;
GLint max_combined_texture_image_units;
GLint max_draw_buffers;
GLint max_renderbuffer_size;
GLint max_samples;
GLint max_uniform_block_size;
GLint max_texture_image_units;
GLint max_combined_texture_image_units;
GLint max_transform_feedback_separate_attribs;
GLint max_uniform_buffer_bindings;
GLint max_uniform_block_size;
GLint max_uniform_buffer_bindings;
GLint num_program_binary_formats;
GLint uniform_buffer_offset_alignment;
} gets = {};

View File

@@ -140,6 +140,7 @@ void* ShaderCompilerService::getUserData(const program_token_t& token) noexcept
ShaderCompilerService::ShaderCompilerService(OpenGLDriver& driver)
: mDriver(driver),
mBlobCache(driver.getContext()),
mCallbackManager(driver),
KHR_parallel_shader_compile(driver.getContext().ext.KHR_parallel_shader_compile) {
}
@@ -219,7 +220,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
token->attributes = std::move(program.getAttributes());
}
token->gl.program = OpenGLBlobCache::retrieve(&token->key, mDriver.mPlatform, program);
token->gl.program = mBlobCache.retrieve(&token->key, mDriver.mPlatform, program);
if (token->gl.program) {
return token;
}
@@ -264,7 +265,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
// caching must be the last thing we do
if (token->key && status == GL_TRUE) {
// Attempt to cache. This calls glGetProgramBinary.
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, glProgram);
mBlobCache.insert(mDriver.mPlatform, token->key, glProgram);
}
});
@@ -317,7 +318,7 @@ ShaderCompilerService::program_token_t ShaderCompilerService::createProgram(
// do this later, maybe depending on CPU usage?
// attempt to cache if we don't have a thread pool (otherwise it's done
// by the pool).
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
}
return true;
@@ -431,7 +432,7 @@ GLuint ShaderCompilerService::initialize(program_token_t& token) noexcept {
mCallbackManager.put(token->handle);
if (token->key) {
OpenGLBlobCache::insert(mDriver.mPlatform, token->key, token->gl.program);
mBlobCache.insert(mDriver.mPlatform, token->key, token->gl.program);
}
} else {
// if we don't have a program yet, block until we get it.

View File

@@ -21,6 +21,7 @@
#include "CallbackManager.h"
#include "CompilerThreadPool.h"
#include "OpenGLBlobCache.h"
#include <backend/CallbackHandler.h>
#include <backend/Program.h>
@@ -95,6 +96,7 @@ public:
private:
OpenGLDriver& mDriver;
OpenGLBlobCache mBlobCache;
CallbackManager mCallbackManager;
CompilerThreadPool mCompilerThreadPool;