Skip to content

Commit

Permalink
improve BlobCache API and compatibility
Browse files Browse the repository at this point in the history
- 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]
  • Loading branch information
pixelflinger committed Oct 26, 2023
1 parent 73b0751 commit f0d5cd3
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 81 deletions.
17 changes: 15 additions & 2 deletions filament/backend/include/backend/Platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class UTILS_PUBLIC Platform {
* 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
Expand All @@ -123,9 +124,21 @@ class UTILS_PUBLIC Platform {
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
Expand Down
14 changes: 8 additions & 6 deletions filament/backend/src/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::hasInsertBlobFunc() const noexcept {
return bool(mInsertBlob);
}

bool Platform::hasBlobFunc() const noexcept {
return mInsertBlob && mRetrieveBlob;
bool Platform::hasRetrieveBlobFunc() const noexcept {
return bool(mRetrieveBlob);
}

void Platform::insertBlob(void const* key, size_t keySize, void const* value, size_t valueSize) {
Expand Down
69 changes: 32 additions & 37 deletions filament/backend/src/opengl/OpenGLBlobCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

#include "OpenGLBlobCache.h"

#include "OpenGLContext.h"

#include <backend/Platform.h>
#include <backend/Program.h>

Expand All @@ -28,17 +30,18 @@ struct OpenGLBlobCache::Blob {
char data[];
};

OpenGLBlobCache::OpenGLBlobCache(OpenGLContext& gl) noexcept
: mCachingSupported(gl.gets.num_program_binary_formats >= 1) {
}

GLuint OpenGLBlobCache::retrieve(BlobCacheKey* outKey, Platform& platform,
Program const& program) noexcept {
Program const& program) const noexcept {
SYSTRACE_CALL();

if (!platform.hasBlobFunc()) {
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
Expand All @@ -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
Expand All @@ -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);
}
}
}
#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)) {
GLenum const error = glGetError();
if (error == GL_NO_ERROR) {
blob->format = format;
memcpy(blob->data, data, programBinarySize);
platform.insertBlob(key.data(), key.size(), blob.get(), size);
}
}
}
#endif
}

} // namespace filament::backend
13 changes: 7 additions & 6 deletions filament/backend/src/opengl/OpenGLBlobCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
BlobCacheKey const& key, GLuint program) noexcept;
GLuint retrieve(BlobCacheKey* key, Platform& platform,
Program const& program) const noexcept;

static void insert(Platform& platform, BlobCacheKey const& key,
GLenum format, void* data, GLsizei programBinarySize) noexcept;
void insert(Platform& platform,
BlobCacheKey const& key, GLuint program) noexcept;

private:
struct Blob;
bool mCachingSupported = false;
};

} // namespace filament::backend
Expand Down
54 changes: 31 additions & 23 deletions filament/backend/src/opengl/OpenGLContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,38 +99,41 @@ OpenGLContext::OpenGLContext() noexcept {

if (mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_1) {
#ifndef FILAMENT_SILENCE_NOT_SUPPORTED_BY_ES2
#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);
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
#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
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions filament/backend/src/opengl/OpenGLContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,14 +153,15 @@ class OpenGLContext {
// 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 = {};

Expand Down
9 changes: 5 additions & 4 deletions filament/backend/src/opengl/ShaderCompilerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
}
});

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions filament/backend/src/opengl/ShaderCompilerService.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include "CallbackManager.h"
#include "CompilerThreadPool.h"
#include "OpenGLBlobCache.h"

#include <backend/CallbackHandler.h>
#include <backend/Program.h>
Expand Down Expand Up @@ -95,6 +96,7 @@ class ShaderCompilerService {

private:
OpenGLDriver& mDriver;
OpenGLBlobCache mBlobCache;
CallbackManager mCallbackManager;
CompilerThreadPool mCompilerThreadPool;

Expand Down

0 comments on commit f0d5cd3

Please sign in to comment.