mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 13:11:19 +01:00
* Initial commit * Update macros * Add GPU Markers * Fix builds without microprofile * minor updates * clang format * Update profiler.cpp * clang format * Name Main Thread * Update profiler_macros.h * Fix end flip * Update fiddle_context_gl.cpp * clang format * Update rive_build_config.lua * Update rive_build_config.lua * forked microprofile so I can use a tag * Update render_context_d3d_impl.cpp * clang Co-authored-by: John White <aliasbinman@gmail.com>
400 lines
12 KiB
C++
400 lines
12 KiB
C++
#include "fiddle_context.hpp"
|
|
|
|
#ifdef RIVE_TOOLS_NO_GLFW
|
|
|
|
std::unique_ptr<FiddleContext> FiddleContext::MakeGLPLS(FiddleContextOptions)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
#else
|
|
|
|
#include "path_fiddle.hpp"
|
|
#include "rive/renderer/rive_renderer.hpp"
|
|
#include "rive/renderer/gl/render_context_gl_impl.hpp"
|
|
#include "rive/renderer/gl/render_target_gl.hpp"
|
|
#include "rive/profiler/profiler_macros.h"
|
|
|
|
#ifdef RIVE_WEBGL
|
|
#include <emscripten/emscripten.h>
|
|
#include <emscripten/html5.h>
|
|
#endif
|
|
|
|
#define GLFW_INCLUDE_NONE
|
|
#include <GLFW/glfw3.h>
|
|
|
|
using namespace rive;
|
|
using namespace rive::gpu;
|
|
|
|
#ifdef RIVE_DESKTOP_GL
|
|
#ifdef DEBUG
|
|
static void GLAPIENTRY err_msg_callback(GLenum source,
|
|
GLenum type,
|
|
GLuint id,
|
|
GLenum severity,
|
|
GLsizei length,
|
|
const GLchar* message,
|
|
const void* userParam)
|
|
{
|
|
if (type == GL_DEBUG_TYPE_ERROR_KHR)
|
|
{
|
|
printf("GL ERROR: %s\n", message);
|
|
fflush(stdout);
|
|
// Don't abort if it's a shader compile error; let our internal handlers
|
|
// print the source (for debugging) and exit on their own.
|
|
if (strstr(message, "SHADER_ID_COMPILE") == nullptr &&
|
|
strstr(message, "SHADER_ID_LINK") == nullptr)
|
|
{
|
|
assert(0);
|
|
}
|
|
}
|
|
else if (type == GL_DEBUG_TYPE_PERFORMANCE_KHR)
|
|
{
|
|
if (strstr(
|
|
message,
|
|
"API_ID_REDUNDANT_FBO performance warning has been generated. "
|
|
"Redundant state change in glBindFramebuffer API call, FBO"))
|
|
{
|
|
return;
|
|
}
|
|
if (strstr(message, "is being recompiled based on GL state") ||
|
|
strstr(message, "shader recompiled due to state change"))
|
|
{
|
|
return;
|
|
}
|
|
if (strcmp(message,
|
|
"Pixel-path performance warning: Pixel transfer is "
|
|
"synchronized with 3D rendering.") == 0)
|
|
{
|
|
return;
|
|
}
|
|
printf("GL PERF: %s\n", message);
|
|
fflush(stdout);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
class FiddleContextGLBase : public FiddleContext
|
|
{
|
|
public:
|
|
~FiddleContextGLBase() override
|
|
{
|
|
glDeleteFramebuffers(1, &m_zoomWindowFBO);
|
|
}
|
|
|
|
float dpiScale(GLFWwindow*) const override
|
|
{
|
|
#if defined(__APPLE__) || defined(RIVE_WEBGL)
|
|
return 2;
|
|
#else
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
void toggleZoomWindow() override
|
|
{
|
|
if (m_zoomWindowFBO)
|
|
{
|
|
glDeleteFramebuffers(1, &m_zoomWindowFBO);
|
|
m_zoomWindowFBO = 0;
|
|
}
|
|
else
|
|
{
|
|
GLuint tex;
|
|
glGenTextures(1, &tex);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, tex);
|
|
glTexStorage2D(GL_TEXTURE_2D,
|
|
1,
|
|
GL_RGB8,
|
|
kZoomWindowWidth,
|
|
kZoomWindowHeight);
|
|
|
|
glGenFramebuffers(1, &m_zoomWindowFBO);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, m_zoomWindowFBO);
|
|
glFramebufferTexture2D(GL_FRAMEBUFFER,
|
|
GL_COLOR_ATTACHMENT0,
|
|
GL_TEXTURE_2D,
|
|
tex,
|
|
0);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
glDeleteTextures(1, &tex);
|
|
}
|
|
}
|
|
|
|
void end(GLFWwindow* window, std::vector<uint8_t>* pixelData) final
|
|
{
|
|
onEnd(pixelData);
|
|
if (m_zoomWindowFBO)
|
|
{
|
|
// Blit the zoom window.
|
|
double xd, yd;
|
|
glfwGetCursorPos(window, &xd, &yd);
|
|
xd *= dpiScale(window);
|
|
yd *= dpiScale(window);
|
|
int width = 0, height = 0;
|
|
glfwGetFramebufferSize(window, &width, &height);
|
|
int x = xd, y = height - yd;
|
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_zoomWindowFBO);
|
|
glBlitFramebuffer(x - kZoomWindowWidth / 2,
|
|
y - kZoomWindowHeight / 2,
|
|
x + kZoomWindowWidth / 2,
|
|
y + kZoomWindowHeight / 2,
|
|
0,
|
|
0,
|
|
kZoomWindowWidth,
|
|
kZoomWindowHeight,
|
|
GL_COLOR_BUFFER_BIT,
|
|
GL_NEAREST);
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
glEnable(GL_SCISSOR_TEST);
|
|
glScissor(0,
|
|
0,
|
|
kZoomWindowWidth * kZoomWindowScale + 2,
|
|
kZoomWindowHeight * kZoomWindowScale + 2);
|
|
glClearColor(.6f, .6f, .6f, 1);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, m_zoomWindowFBO);
|
|
glBlitFramebuffer(0,
|
|
0,
|
|
kZoomWindowWidth,
|
|
kZoomWindowHeight,
|
|
0,
|
|
0,
|
|
kZoomWindowWidth * kZoomWindowScale,
|
|
kZoomWindowHeight * kZoomWindowScale,
|
|
GL_COLOR_BUFFER_BIT,
|
|
GL_NEAREST);
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
RIVE_PROF_ENDFRAME()
|
|
}
|
|
|
|
protected:
|
|
virtual void onEnd(std::vector<uint8_t>* pixelData) = 0;
|
|
|
|
private:
|
|
GLuint m_zoomWindowFBO = 0;
|
|
};
|
|
|
|
class FiddleContextGL : public FiddleContextGLBase
|
|
{
|
|
public:
|
|
FiddleContextGL(FiddleContextOptions options)
|
|
{
|
|
#ifdef RIVE_DESKTOP_GL
|
|
// Load the OpenGL API using glad.
|
|
if (!gladLoadCustomLoader(
|
|
reinterpret_cast<GLADloadfunc>(glfwGetProcAddress)))
|
|
{
|
|
fprintf(stderr, "Failed to initialize glad.\n");
|
|
abort();
|
|
}
|
|
#endif
|
|
|
|
printf("==== GL GPU: %s ====\n", glGetString(GL_RENDERER));
|
|
#if 0
|
|
int n;
|
|
glGetIntegerv(GL_NUM_EXTENSIONS, &n);
|
|
for (size_t i = 0; i < n; ++i)
|
|
{
|
|
printf(" %s\n", glGetStringi(GL_EXTENSIONS, i));
|
|
}
|
|
#endif
|
|
|
|
#ifdef RIVE_DESKTOP_GL
|
|
#ifdef DEBUG
|
|
if (GLAD_GL_KHR_debug)
|
|
{
|
|
glEnable(GL_DEBUG_OUTPUT_KHR);
|
|
glDebugMessageControlKHR(GL_DONT_CARE,
|
|
GL_DONT_CARE,
|
|
GL_DONT_CARE,
|
|
0,
|
|
NULL,
|
|
GL_TRUE);
|
|
glDebugMessageCallbackKHR(&err_msg_callback, nullptr);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
m_renderContext = RenderContextGLImpl::MakeContext({
|
|
.shaderCompilationMode = options.shaderCompilationMode,
|
|
.disableFragmentShaderInterlock = options.disableRasterOrdering,
|
|
});
|
|
if (!m_renderContext)
|
|
{
|
|
fprintf(stderr, "Failed to create a RiveRenderContext for GL.\n");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
rive::Factory* factory() final { return m_renderContext.get(); }
|
|
|
|
RenderContext* renderContextOrNull() final { return m_renderContext.get(); }
|
|
|
|
RenderContextGLImpl* renderContextGLImpl() const final
|
|
{
|
|
return m_renderContext->static_impl_cast<RenderContextGLImpl>();
|
|
}
|
|
|
|
RenderTarget* renderTargetOrNull() final { return m_renderTarget.get(); }
|
|
|
|
void onSizeChanged(GLFWwindow* window,
|
|
int width,
|
|
int height,
|
|
uint32_t sampleCount) final
|
|
{
|
|
m_renderTarget =
|
|
make_rcp<FramebufferRenderTargetGL>(width, height, 0, sampleCount);
|
|
glViewport(0, 0, width, height);
|
|
}
|
|
|
|
std::unique_ptr<Renderer> makeRenderer(int width, int height) final
|
|
{
|
|
return std::make_unique<RiveRenderer>(m_renderContext.get());
|
|
}
|
|
|
|
void begin(const RenderContext::FrameDescriptor& frameDescriptor) final
|
|
{
|
|
renderContextGLImpl()->invalidateGLState();
|
|
m_renderContext->beginFrame(frameDescriptor);
|
|
}
|
|
|
|
void flushPLSContext(RenderTarget* offscreenRenderTarget) final
|
|
{
|
|
m_renderContext->flush({
|
|
.renderTarget = offscreenRenderTarget != nullptr
|
|
? offscreenRenderTarget
|
|
: m_renderTarget.get(),
|
|
});
|
|
}
|
|
|
|
void onEnd(std::vector<uint8_t>* pixelData) final
|
|
{
|
|
flushPLSContext(nullptr);
|
|
renderContextGLImpl()->unbindGLInternalResources();
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
if (pixelData)
|
|
{
|
|
pixelData->resize(m_renderTarget->height() *
|
|
m_renderTarget->width() * 4);
|
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
|
glReadPixels(0,
|
|
0,
|
|
m_renderTarget->width(),
|
|
m_renderTarget->height(),
|
|
GL_RGBA,
|
|
GL_UNSIGNED_BYTE,
|
|
pixelData->data());
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<RenderContext> m_renderContext;
|
|
rcp<RenderTargetGL> m_renderTarget;
|
|
};
|
|
|
|
std::unique_ptr<FiddleContext> FiddleContext::MakeGLPLS(
|
|
FiddleContextOptions options)
|
|
{
|
|
return std::make_unique<FiddleContextGL>(options);
|
|
}
|
|
|
|
#ifndef RIVE_SKIA
|
|
|
|
std::unique_ptr<FiddleContext> FiddleContext::MakeGLSkia() { return nullptr; }
|
|
|
|
#else
|
|
|
|
#include "skia_factory.hpp"
|
|
#include "skia_renderer.hpp"
|
|
#include "skia/include/core/SkCanvas.h"
|
|
#include "skia/include/core/SkSurface.h"
|
|
#include "skia/include/gpu/GrDirectContext.h"
|
|
#include "skia/include/gpu/gl/GrGLAssembleInterface.h"
|
|
#include "skia/include/gpu/gl/GrGLInterface.h"
|
|
#include "include/effects/SkImageFilters.h"
|
|
|
|
static GrGLFuncPtr get_skia_gl_proc_address(void* ctx, const char name[])
|
|
{
|
|
return glfwGetProcAddress(name);
|
|
}
|
|
|
|
class FiddleContextGLSkia : public FiddleContextGLBase
|
|
{
|
|
public:
|
|
FiddleContextGLSkia() :
|
|
m_grContext(GrDirectContext::MakeGL(
|
|
GrGLMakeAssembledInterface(nullptr, get_skia_gl_proc_address)))
|
|
{
|
|
if (!m_grContext)
|
|
{
|
|
fprintf(stderr, "GrDirectContext::MakeGL failed.\n");
|
|
abort();
|
|
}
|
|
}
|
|
|
|
rive::Factory* factory() final { return &m_factory; }
|
|
|
|
RenderContext* renderContextOrNull() final { return nullptr; }
|
|
|
|
RenderTarget* renderTargetOrNull() final { return nullptr; }
|
|
|
|
std::unique_ptr<Renderer> makeRenderer(int width, int height) final
|
|
{
|
|
GrBackendRenderTarget backendRT(width,
|
|
height,
|
|
1 /*samples*/,
|
|
0 /*stencilBits*/,
|
|
{0 /*fbo 0*/, GL_RGBA8});
|
|
|
|
SkSurfaceProps surfProps(0, kUnknown_SkPixelGeometry);
|
|
|
|
m_skSurface =
|
|
SkSurface::MakeFromBackendRenderTarget(m_grContext.get(),
|
|
backendRT,
|
|
kBottomLeft_GrSurfaceOrigin,
|
|
kRGBA_8888_SkColorType,
|
|
nullptr,
|
|
&surfProps);
|
|
if (!m_skSurface)
|
|
{
|
|
fprintf(stderr, "SkSurface::MakeFromBackendRenderTarget failed.\n");
|
|
abort();
|
|
}
|
|
return std::make_unique<SkiaRenderer>(m_skSurface->getCanvas());
|
|
}
|
|
|
|
void begin(const RenderContext::FrameDescriptor& frameDescriptor) final
|
|
{
|
|
m_skSurface->getCanvas()->clear(frameDescriptor.clearColor);
|
|
m_grContext->resetContext();
|
|
m_skSurface->getCanvas()->save();
|
|
}
|
|
|
|
void onEnd(std::vector<uint8_t>* pixelData) final
|
|
{
|
|
m_skSurface->getCanvas()->restore();
|
|
m_skSurface->flush();
|
|
}
|
|
|
|
void flushPLSContext(RenderTarget* offscreenRenderTarget) final {}
|
|
|
|
private:
|
|
SkiaFactory m_factory;
|
|
const sk_sp<GrDirectContext> m_grContext;
|
|
sk_sp<SkSurface> m_skSurface;
|
|
};
|
|
|
|
std::unique_ptr<FiddleContext> FiddleContext::MakeGLSkia()
|
|
{
|
|
return std::make_unique<FiddleContextGLSkia>();
|
|
}
|
|
#endif
|
|
|
|
#endif
|