Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions GPU/GPUTracking/Definitions/GPUSettingsList.h
Original file line number Diff line number Diff line change
Expand Up @@ -500,12 +500,12 @@ AddOption(camYUp, bool, false, "", 0, "Orient the camera such that the y-axis is
AddOption(cameraMode, int32_t, 0, "", 0, "Camera mode")
AddOption(fullScreen, bool, false, "", 0, "Full Screen")
AddOption(maximized, bool, true, "", 0, "Maximized window")
AddOption(rendererCompatSmoothing, bool, false, "", 0, "Use compat smoothing (if available) of instad of shader for smooth lines / points")
AddOption(rendererCompatSmoothing, bool, false, "", 0, "Use compat smoothing (if available) instead of shader for smooth lines / points")
AddOption(drawQualityMSAA, int32_t, 0, "", 0, "MultiSample Anti Aliasing")
AddOption(drawQualityDownsampleFSAA, int32_t, 0, "", 0, "Downsampling Anti Aliasing")
AddOption(drawQualityVSync, bool, true, "", 0, "Enable Vertical Sync")
AddOption(maxFPSRate, bool, false, "", 0, "Do not limit FPS but run at maximum possible rate")
AddOption(fpsRate, int32_t, 100, "", 0, "Target frame rate (frames per second) if not running at maximum rate (0 = no limit)")
AddOption(fpsLimit, int32_t, 1, "", 0, "FPS limit: 0 = none (maximum rate), 1 = display refresh rate (no limit without VSync), 2 = fpsRate")
AddOption(fpsRate, int32_t, 100, "", 0, "Target frame rate (frames per second) for fpsLimit 2, or if the backend cannot limit to the refresh rate (0 = no limit)")
AddOption(useGLIndirectDraw, bool, true, "", 0, "Use OpenGL indirect draws to reduce number of draw calls")
AddOption(screenshotScaleFactor, int32_t, 1, "", 0, "Resolution scale factor when taking screenshots")
AddOption(fov, int32_t, 45, "", 0, "Display FOV")
Expand Down
2 changes: 2 additions & 0 deletions GPU/GPUTracking/display/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ if(GPUCA_EVENT_DISPLAY_VULKAN OR GPUCA_EVENT_DISPLAY_OPENGL)
shaders/vertexSmoothPoint.vert
shaders/vertexTexture.vert
shaders/vertexPassthrough.vert
shaders/vertexFullscreen.vert
shaders/fragmentDownsample.frag
shaders/fragment.frag
shaders/fragmentSmoothPoint.frag
shaders/vertexSmoothLine.vert
Expand Down
12 changes: 11 additions & 1 deletion GPU/GPUTracking/display/GPUDisplay.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,14 @@ void GPUDisplay::DrawGLScene_drawCommands()

void GPUDisplay::DrawGLScene_internal(float animateTime, bool renderToMixBuffer) // negative time = no mixing
{
if (mRequestScreenshot || mAnimateScreenshot) {
const uint32_t factor = std::max(1, mCfgR.drawQualityDownsampleFSAA) * std::max(1, mCfgR.screenshotScaleFactor);
if (std::max(mBackend->mScreenWidth, mBackend->mScreenHeight) * factor > mBackend->mMaxRenderSize) {
GPUError("Screenshot not taken: requested render size %u x %u (window x FSAA x screenshot scale) exceeds the maximum size %u x %u", mBackend->mScreenWidth * factor, mBackend->mScreenHeight * factor, mBackend->mMaxRenderSize, mBackend->mMaxRenderSize);
mRequestScreenshot = false;
mAnimateScreenshot = 0;
}
}
bool doScreenshot = (mRequestScreenshot || mAnimateScreenshot) && animateTime < 0;

updateOptions();
Expand Down Expand Up @@ -666,7 +674,9 @@ void GPUDisplay::DrawGLScene_internal(float animateTime, bool renderToMixBuffer)
nextViewMatrix = nextViewMatrix * *mModelMatrix;
const float zFar = ((mParam->par.continuousTracking ? (mMaxClusterZ * GL_SCALE_FACTOR) : 8.f) + 50.f) * 2.f;
const hmm_mat4 proj = HMM_Perspective(mCfgR.fov, (float)mBackend->mRenderWidth / (float)mBackend->mRenderHeight, 0.1f, zFar);
mBackend->prepareDraw(proj, nextViewMatrix, doScreenshot || mRequestScreenshot, renderToMixBuffer, mixSlaveImage);
if (!mBackend->prepareDraw(proj, nextViewMatrix, doScreenshot || mRequestScreenshot, renderToMixBuffer, mixSlaveImage)) {
return; // No image available (e.g. hidden window), retry with the next frame
}
mBackend->pointSizeFactor(1);
mBackend->lineWidthFactor(1);

Expand Down
1 change: 1 addition & 0 deletions GPU/GPUTracking/display/GPUDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ class GPUDisplay : public GPUDisplayInterface
HighResTimer mAnimationTimer;
int32_t mAnimationFrame = 0;
int32_t mAnimationLastBase = 0;
int32_t mAnimationMixBase = -1; // Target keyframe of the current config blend (mixing), -1 = none
int32_t mAnimateScreenshot = 0;
int32_t mAnimationExport = 0;
bool mAnimationChangeConfig = true;
Expand Down
14 changes: 13 additions & 1 deletion GPU/GPUTracking/display/backend/GPUDisplayBackend.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ void GPUDisplayBackend::loadFont()
return;
}
if (FT_New_Face(ft, fontName.c_str(), 0, &face)) {
GPUError("Error loading freetypoe font");
GPUError("Error loading freetype font");
FT_Done_FreeType(ft);
return;
}

Expand All @@ -134,6 +135,8 @@ void GPUDisplayBackend::loadFont()
for (uint32_t i = 0; i < 128; i++) {
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
GPUError("Error loading freetype symbol");
FT_Done_Face(face);
FT_Done_FreeType(ft);
return;
}
const auto& glyph = face->glyph;
Expand Down Expand Up @@ -171,6 +174,15 @@ void GPUDisplayBackend::fillIndirectCmdBuffer()
}
}

int32_t GPUDisplayBackend::fpsLimitMode() const
{
const auto& cfg = mDisplay->cfgR();
if (cfg.fpsLimit == FPS_LIMIT_VSYNC) {
return !cfg.drawQualityVSync ? FPS_LIMIT_NONE : (canLimitToVSync() ? FPS_LIMIT_VSYNC : FPS_LIMIT_RATE);
}
return cfg.fpsLimit;
}

float GPUDisplayBackend::getDownsampleFactor(bool screenshot)
{
float factor = 1.0f;
Expand Down
8 changes: 7 additions & 1 deletion GPU/GPUTracking/display/backend/GPUDisplayBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class GPUDisplayBackend
virtual void ActivateColor(std::array<float, 4>& color) = 0;
virtual void setQuality() {};
virtual void SetVSync(bool enable) {};
enum fpsLimitModes : int32_t { FPS_LIMIT_NONE = 0,
FPS_LIMIT_VSYNC = 1,
FPS_LIMIT_RATE = 2 }; // Values of GPUSettingsDisplayRenderer::fpsLimit
virtual bool canLimitToVSync() const { return false; } // Rendering is throttled to the refresh rate with VSync (blocking buffer swap / present wait)
int32_t fpsLimitMode() const; // Effective mode: VSync limit without VSync = none, VSync limit not supported by the backend = fpsRate
virtual bool backendNeedRedraw() { return true; }
virtual void setDepthBuffer() = 0;
virtual int32_t InitBackendA() = 0;
Expand All @@ -85,7 +90,7 @@ class GPUDisplayBackend
void updateFontScale(float scale); // Rasterize the font again if the display (HiDPI) scale changed
void ExitBackend();
virtual void loadDataToGPU(size_t totalVertizes) = 0;
virtual void prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot = false, bool toMixBuffer = false, float includeMixImage = 0.f) = 0;
virtual bool prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot = false, bool toMixBuffer = false, float includeMixImage = 0.f) = 0; // Returns false if the frame must be skipped (no swapchain image available)
virtual void finishDraw(bool doScreenshot, bool toMixBuffer = false, float includeMixImage = 0.f) = 0;
virtual void finishFrame(bool doScreenshot, bool toMixBuffer = false, float includeMixImage = 0.f) = 0;
virtual void prepareText() = 0;
Expand Down Expand Up @@ -126,6 +131,7 @@ class GPUDisplayBackend

uint32_t mRenderWidth = 0;
uint32_t mRenderHeight = 0;
uint32_t mMaxRenderSize = UINT32_MAX; // Maximum width / height of render targets, set by the backend
uint32_t mScreenWidth = 0;
uint32_t mScreenHeight = 0;

Expand Down
2 changes: 1 addition & 1 deletion GPU/GPUTracking/display/backend/GPUDisplayBackendNone.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class GPUDisplayBackendNone : public GPUDisplayBackend
int32_t InitBackendA() override;
void ExitBackendA() override {}
void loadDataToGPU(size_t totalVertizes) override {}
void prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot, bool toMixBuffer, float includeMixImage) override {}
bool prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot, bool toMixBuffer, float includeMixImage) override { return true; }
void finishDraw(bool doScreenshot, bool toMixBuffer, float includeMixImage) override {}
void finishFrame(bool doScreenshot, bool toMixBuffer, float includeMixImage) override {}
void prepareText() override {}
Expand Down
94 changes: 71 additions & 23 deletions GPU/GPUTracking/display/backend/GPUDisplayBackendOpenGL.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ int32_t GPUDisplayBackendOpenGL::ExtInit()
#endif
}

bool GPUDisplayBackendOpenGL::canLimitToVSync() const
{
return mDisplay->frontend()->canSetVSync();
}

bool GPUDisplayBackendOpenGL::CoreProfile()
{
#ifdef GPUCA_DISPLAY_OPENGL_CORE
Expand Down Expand Up @@ -310,6 +315,11 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
GPUError("Unsupported OpenGL runtime %d.%d < %d.%d", glVersion[0], glVersion[1], GPUDisplayFrontend::GL_MIN_VERSION_MAJOR, GPUDisplayFrontend::GL_MIN_VERSION_MINOR);
return (1);
}
for (GLenum limit : {GL_MAX_TEXTURE_SIZE, GL_MAX_RENDERBUFFER_SIZE, GL_MAX_FRAMEBUFFER_WIDTH, GL_MAX_FRAMEBUFFER_HEIGHT}) {
GLint value = 0;
glGetIntegerv(limit, &value);
mMaxRenderSize = std::min<uint32_t>(mMaxRenderSize, value);
}
mVBOId.resize(GPUTPCGeometry::NSECTORS);
CHKERR(glCreateBuffers(mVBOId.size(), mVBOId.data()));
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0]));
Expand All @@ -325,11 +335,13 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
CHKERR(mVertexShaderTexture = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexTexture_vert_spv_start, _binary_opengl_vertexTexture_vert_spv_len));
CHKERR(mFragmentShaderTexture = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentTexture_frag_spv_start, _binary_opengl_fragmentTexture_frag_spv_len));
CHKERR(mFragmentShaderText = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentText_frag_spv_start, _binary_opengl_fragmentText_frag_spv_len));
CHKERR(mVertexShaderFullscreen = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexFullscreen_vert_spv_start, _binary_opengl_vertexFullscreen_vert_spv_len));
CHKERR(mFragmentShaderDownsample = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentDownsample_frag_spv_start, _binary_opengl_fragmentDownsample_frag_spv_len));
CHKERR(mVertexShaderSmoothPoint = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexSmoothPoint_vert_spv_start, _binary_opengl_vertexSmoothPoint_vert_spv_len));
CHKERR(mFragmentShaderSmoothPoint = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentSmoothPoint_frag_spv_start, _binary_opengl_fragmentSmoothPoint_frag_spv_len));
CHKERR(mVertexShaderSmoothLine = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexSmoothLine_vert_spv_start, _binary_opengl_vertexSmoothLine_vert_spv_len));
CHKERR(mFragmentShaderSmoothLine = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentSmoothLine_frag_spv_start, _binary_opengl_fragmentSmoothLine_frag_spv_len));
if (checkShaderStatus(mVertexShader) || checkShaderStatus(mFragmentShader) || checkShaderStatus(mVertexShaderSmoothPoint) || checkShaderStatus(mFragmentShaderSmoothPoint) || checkShaderStatus(mVertexShaderSmoothLine) || checkShaderStatus(mFragmentShaderSmoothLine) || checkShaderStatus(mVertexShaderTexture) || checkShaderStatus(mFragmentShaderTexture) || checkShaderStatus(mFragmentShaderText)) {
if (checkShaderStatus(mVertexShader) || checkShaderStatus(mFragmentShader) || checkShaderStatus(mVertexShaderSmoothPoint) || checkShaderStatus(mFragmentShaderSmoothPoint) || checkShaderStatus(mVertexShaderSmoothLine) || checkShaderStatus(mFragmentShaderSmoothLine) || checkShaderStatus(mVertexShaderTexture) || checkShaderStatus(mFragmentShaderTexture) || checkShaderStatus(mFragmentShaderText) || checkShaderStatus(mVertexShaderFullscreen) || checkShaderStatus(mFragmentShaderDownsample)) {
return 1;
}
CHKERR(mShaderProgram = glCreateProgram());
Expand Down Expand Up @@ -367,6 +379,13 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
if (checkProgramStatus(mShaderProgramTexture)) {
return 1;
}
CHKERR(mShaderProgramDownsample = glCreateProgram());
CHKERR(glAttachShader(mShaderProgramDownsample, mVertexShaderFullscreen));
CHKERR(glAttachShader(mShaderProgramDownsample, mFragmentShaderDownsample));
CHKERR(glLinkProgram(mShaderProgramDownsample));
if (checkProgramStatus(mShaderProgramDownsample)) {
return 1;
}
CHKERR(glGenVertexArrays(1, &mVertexArray));

CHKERR(glGenVertexArrays(1, &VAO_texture));
Expand Down Expand Up @@ -399,6 +418,9 @@ void GPUDisplayBackendOpenGL::ExitBackendA()
CHKERR(glDeleteProgram(mShaderProgramText));
CHKERR(glDeleteShader(mFragmentShaderText));
CHKERR(glDeleteProgram(mShaderProgramTexture));
CHKERR(glDeleteProgram(mShaderProgramDownsample));
CHKERR(glDeleteShader(mVertexShaderFullscreen));
CHKERR(glDeleteShader(mFragmentShaderDownsample));
CHKERR(glDeleteShader(mVertexShaderTexture));
CHKERR(glDeleteShader(mFragmentShaderTexture));

Expand Down Expand Up @@ -454,11 +476,14 @@ void GPUDisplayBackendOpenGL::loadDataToGPU(size_t totalVertizes)
}
}

void GPUDisplayBackendOpenGL::prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot, bool toMixBuffer, float includeMixImage)
bool GPUDisplayBackendOpenGL::prepareDraw(const hmm_mat4& proj, const hmm_mat4& view, bool requestScreenshot, bool toMixBuffer, float includeMixImage)
{
if (mDisplay->updateRenderPipeline() || mDownsampleFactor != getDownsampleFactor(requestScreenshot)) {
updateRenderer(requestScreenshot);
}
if (toMixBuffer && !mMixBuffer.created) { // Only allocated when mixing is used, freed with the other offscreen buffers
createFB(mMixBuffer, true, true, false, mRenderWidth, mRenderHeight);
}
if (mOffscreenBufferMSAA.created) {
setFrameBuffer(mOffscreenBufferMSAA.fb_id);
} else if (toMixBuffer) {
Expand Down Expand Up @@ -526,6 +551,7 @@ void GPUDisplayBackendOpenGL::prepareDraw(const hmm_mat4& proj, const hmm_mat4&
CHKERR(glNamedBufferSubData(mFieldModelViewBuffer, 0, sizeof(modelViewProj), &modelViewProj));
}
}
return true;
}

void GPUDisplayBackendOpenGL::finishDraw(bool doScreenshot, bool toMixBuffer, float includeMixImage)
Expand All @@ -540,16 +566,18 @@ void GPUDisplayBackendOpenGL::finishDraw(bool doScreenshot, bool toMixBuffer, fl
CHKERR(glUseProgram(0));
}

if (mDisplay->cfgR().drawQualityMSAA) {
if (mOffscreenBufferMSAA.created) {
uint32_t dstId = toMixBuffer ? mMixBuffer.fb_id : (mDownsampleFactor != 1 ? mOffscreenBuffer.fb_id : 0);
CHKERR(glBlitNamedFramebuffer(mOffscreenBufferMSAA.fb_id, dstId, 0, 0, mRenderWidth, mRenderHeight, 0, 0, mRenderWidth, mRenderHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR));
}
if (includeMixImage > 0) {
setFrameBuffer(mDownsampleFactor != 1 ? mOffscreenBuffer.fb_id : 0);
mixImages(includeMixImage);
}
if (mDownsampleFactor != 1 && !toMixBuffer) {
if (mDownsampleFactor == 2 && !toMixBuffer) { // The linear blit is only exact for factor 2
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, 0, 0, 0, mRenderWidth, mRenderHeight, 0, 0, mScreenWidth, mScreenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR));
} else if (mDownsampleFactor != 1 && !toMixBuffer) {
drawDownsample(mOffscreenBuffer.fbCol_id, 0, mScreenWidth, mScreenHeight, mDownsampleFactor);
}

if (doScreenshot && !toMixBuffer) {
Expand All @@ -565,7 +593,12 @@ void GPUDisplayBackendOpenGL::readImageToPixels()
GLfb tmpBuffer;
if (mDisplay->cfgR().drawQualityDownsampleFSAA && mDisplay->cfgR().screenshotScaleFactor != 1) {
createFB(tmpBuffer, false, true, false, width, height);
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, tmpBuffer.fb_id, 0, 0, mRenderWidth, mRenderHeight, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR));
const int32_t factor = mRenderWidth / width;
if (factor > 2) {
drawDownsample(mOffscreenBuffer.fbCol_id, tmpBuffer.fb_id, width, height, factor);
} else {
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, tmpBuffer.fb_id, 0, 0, mRenderWidth, mRenderHeight, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR));
}
}
setFrameBuffer(tmpBuffer.created ? tmpBuffer.fb_id : (scaleFactor != 1 ? mOffscreenBuffer.fb_id : 0));
CHKERR(glPixelStorei(GL_PACK_ALIGNMENT, 1));
Expand Down Expand Up @@ -611,6 +644,25 @@ void GPUDisplayBackendOpenGL::finishText()
}
}

void GPUDisplayBackendOpenGL::drawDownsample(uint32_t srcTexture, uint32_t dstFramebuffer, uint32_t width, uint32_t height, int32_t factor)
{
setFrameBuffer(dstFramebuffer);
CHKERR(glViewport(0, 0, width, height));
CHKERR(glDisable(GL_DEPTH_TEST));
CHKERR(glDisable(GL_BLEND));
CHKERR(glUseProgram(mShaderProgramDownsample));
CHKERR(glUniform1i(UNIFORM_LOCATION_COLOR, factor));
CHKERR(glActiveTexture(GL_TEXTURE0));
CHKERR(glBindTexture(GL_TEXTURE_2D, srcTexture));
CHKERR(glBindVertexArray(VAO_texture)); // Any VAO, the full-screen triangle has no vertex input
CHKERR(glDrawArrays(GL_TRIANGLES, 0, 3));
CHKERR(glBindVertexArray(0));
CHKERR(glBindTexture(GL_TEXTURE_2D, 0));
CHKERR(glUseProgram(0));
CHKERR(glEnable(GL_BLEND));
setDepthBuffer();
}

void GPUDisplayBackendOpenGL::mixImages(float mixSlaveImage)
{
hmm_mat4 proj = HMM_Orthographic(0.f, mRenderWidth, 0.f, mRenderHeight, -1.f, 1.f);
Expand Down Expand Up @@ -745,8 +797,8 @@ void GPUDisplayBackendOpenGL::OpenGLPrint(const char* s, float x, float y, float
if (smoothFont()) {
scale *= 0.25f; // Font size is 48 to have nice bitmap, scale to size 12
}
for (const char* c = s; *c; c++) {
if ((int32_t)*c > (int32_t)mFontSymbols.size()) {
for (const unsigned char* c = (const unsigned char*)s; *c; c++) {
if ((int32_t)*c >= (int32_t)mFontSymbols.size()) {
GPUError("Trying to draw unsupported symbol: %d > %d\n", (int32_t)*c, (int32_t)mFontSymbols.size());
continue;
}
Expand Down Expand Up @@ -795,20 +847,6 @@ void GPUDisplayBackendOpenGL::resizeScene(uint32_t width, uint32_t height)
mScreenHeight = height;

updateRenderer(false);

float vertices[6][4] = {
{0, (float)mRenderHeight, 0.0f, 1.0f},
{0, 0, 0.0f, 0.0f},
{(float)mRenderWidth, 0, 1.0f, 0.0f},
{0, (float)mRenderHeight, 0.0f, 1.0f},
{(float)mRenderWidth, 0, 1.0f, 0.0f},
{(float)mRenderWidth, (float)mRenderHeight, 1.0f, 1.0f}};
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, VBO_texture));
CHKERR(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices));
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, 0));
if (!mDisplay->useMultiVBO()) {
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0])); // If we don't use multiple buffers, we keep the default buffer bound
}
}

void GPUDisplayBackendOpenGL::updateRenderer(bool withScreenshot)
Expand All @@ -821,8 +859,18 @@ void GPUDisplayBackendOpenGL::updateRenderer(bool withScreenshot)
createFB(mOffscreenBufferMSAA, false, true, true, mRenderWidth, mRenderHeight);
}
if (mDownsampleFactor != 1) {
createFB(mOffscreenBuffer, false, true, false, mRenderWidth, mRenderHeight);
createFB(mOffscreenBuffer, mDownsampleFactor != 2, true, false, mRenderWidth, mRenderHeight); // Texture for shader downsampling (factor != 2), screenshot downsampling uses the shader only if this factor is != 2 as well
}
createFB(mMixBuffer, true, true, false, mRenderWidth, mRenderHeight);
setQuality();

float vertices[6][4] = {// Mix quad at render size
{0, (float)mRenderHeight, 0.0f, 1.0f},
{0, 0, 0.0f, 0.0f},
{(float)mRenderWidth, 0, 1.0f, 0.0f},
{0, (float)mRenderHeight, 0.0f, 1.0f},
{(float)mRenderWidth, 0, 1.0f, 0.0f},
{(float)mRenderWidth, (float)mRenderHeight, 1.0f, 1.0f}};
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, VBO_texture));
CHKERR(glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices));
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mDisplay->useMultiVBO() ? 0 : mVBOId[0])); // If we don't use multiple buffers, we keep the default buffer bound (also called from prepareDraw before the vertex pointers are set)
}
Loading
Loading