Skip to content

Commit a3f4839

Browse files
committed
GPU Display: Use fragment shader to downsample >2 FSAA, since blit has poor quality
1 parent 2c6742c commit a3f4839

9 files changed

Lines changed: 204 additions & 15 deletions

‎GPU/GPUTracking/display/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,8 @@ if(GPUCA_EVENT_DISPLAY_VULKAN OR GPUCA_EVENT_DISPLAY_OPENGL)
260260
shaders/vertexSmoothPoint.vert
261261
shaders/vertexTexture.vert
262262
shaders/vertexPassthrough.vert
263+
shaders/vertexFullscreen.vert
264+
shaders/fragmentDownsample.frag
263265
shaders/fragment.frag
264266
shaders/fragmentSmoothPoint.frag
265267
shaders/vertexSmoothLine.vert

‎GPU/GPUTracking/display/GPUDisplay.cxx‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,14 @@ void GPUDisplay::DrawGLScene_drawCommands()
629629

630630
void GPUDisplay::DrawGLScene_internal(float animateTime, bool renderToMixBuffer) // negative time = no mixing
631631
{
632+
if (mRequestScreenshot || mAnimateScreenshot) {
633+
const uint32_t factor = std::max(1, mCfgR.drawQualityDownsampleFSAA) * std::max(1, mCfgR.screenshotScaleFactor);
634+
if (std::max(mBackend->mScreenWidth, mBackend->mScreenHeight) * factor > mBackend->mMaxRenderSize) {
635+
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);
636+
mRequestScreenshot = false;
637+
mAnimateScreenshot = 0;
638+
}
639+
}
632640
bool doScreenshot = (mRequestScreenshot || mAnimateScreenshot) && animateTime < 0;
633641

634642
updateOptions();

‎GPU/GPUTracking/display/backend/GPUDisplayBackend.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class GPUDisplayBackend
126126

127127
uint32_t mRenderWidth = 0;
128128
uint32_t mRenderHeight = 0;
129+
uint32_t mMaxRenderSize = UINT32_MAX; // Maximum width / height of render targets, set by the backend
129130
uint32_t mScreenWidth = 0;
130131
uint32_t mScreenHeight = 0;
131132

‎GPU/GPUTracking/display/backend/GPUDisplayBackendOpenGL.cxx‎

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,11 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
310310
GPUError("Unsupported OpenGL runtime %d.%d < %d.%d", glVersion[0], glVersion[1], GPUDisplayFrontend::GL_MIN_VERSION_MAJOR, GPUDisplayFrontend::GL_MIN_VERSION_MINOR);
311311
return (1);
312312
}
313+
for (GLenum limit : {GL_MAX_TEXTURE_SIZE, GL_MAX_RENDERBUFFER_SIZE, GL_MAX_FRAMEBUFFER_WIDTH, GL_MAX_FRAMEBUFFER_HEIGHT}) {
314+
GLint value = 0;
315+
glGetIntegerv(limit, &value);
316+
mMaxRenderSize = std::min<uint32_t>(mMaxRenderSize, value);
317+
}
313318
mVBOId.resize(GPUTPCGeometry::NSECTORS);
314319
CHKERR(glCreateBuffers(mVBOId.size(), mVBOId.data()));
315320
CHKERR(glBindBuffer(GL_ARRAY_BUFFER, mVBOId[0]));
@@ -325,11 +330,13 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
325330
CHKERR(mVertexShaderTexture = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexTexture_vert_spv_start, _binary_opengl_vertexTexture_vert_spv_len));
326331
CHKERR(mFragmentShaderTexture = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentTexture_frag_spv_start, _binary_opengl_fragmentTexture_frag_spv_len));
327332
CHKERR(mFragmentShaderText = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentText_frag_spv_start, _binary_opengl_fragmentText_frag_spv_len));
333+
CHKERR(mVertexShaderFullscreen = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexFullscreen_vert_spv_start, _binary_opengl_vertexFullscreen_vert_spv_len));
334+
CHKERR(mFragmentShaderDownsample = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentDownsample_frag_spv_start, _binary_opengl_fragmentDownsample_frag_spv_len));
328335
CHKERR(mVertexShaderSmoothPoint = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexSmoothPoint_vert_spv_start, _binary_opengl_vertexSmoothPoint_vert_spv_len));
329336
CHKERR(mFragmentShaderSmoothPoint = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentSmoothPoint_frag_spv_start, _binary_opengl_fragmentSmoothPoint_frag_spv_len));
330337
CHKERR(mVertexShaderSmoothLine = loadShader(GL_VERTEX_SHADER, _binary_opengl_vertexSmoothLine_vert_spv_start, _binary_opengl_vertexSmoothLine_vert_spv_len));
331338
CHKERR(mFragmentShaderSmoothLine = loadShader(GL_FRAGMENT_SHADER, _binary_opengl_fragmentSmoothLine_frag_spv_start, _binary_opengl_fragmentSmoothLine_frag_spv_len));
332-
if (checkShaderStatus(mVertexShader) || checkShaderStatus(mFragmentShader) || checkShaderStatus(mVertexShaderSmoothPoint) || checkShaderStatus(mFragmentShaderSmoothPoint) || checkShaderStatus(mVertexShaderSmoothLine) || checkShaderStatus(mFragmentShaderSmoothLine) || checkShaderStatus(mVertexShaderTexture) || checkShaderStatus(mFragmentShaderTexture) || checkShaderStatus(mFragmentShaderText)) {
339+
if (checkShaderStatus(mVertexShader) || checkShaderStatus(mFragmentShader) || checkShaderStatus(mVertexShaderSmoothPoint) || checkShaderStatus(mFragmentShaderSmoothPoint) || checkShaderStatus(mVertexShaderSmoothLine) || checkShaderStatus(mFragmentShaderSmoothLine) || checkShaderStatus(mVertexShaderTexture) || checkShaderStatus(mFragmentShaderTexture) || checkShaderStatus(mFragmentShaderText) || checkShaderStatus(mVertexShaderFullscreen) || checkShaderStatus(mFragmentShaderDownsample)) {
333340
return 1;
334341
}
335342
CHKERR(mShaderProgram = glCreateProgram());
@@ -367,6 +374,13 @@ int32_t GPUDisplayBackendOpenGL::InitBackendA()
367374
if (checkProgramStatus(mShaderProgramTexture)) {
368375
return 1;
369376
}
377+
CHKERR(mShaderProgramDownsample = glCreateProgram());
378+
CHKERR(glAttachShader(mShaderProgramDownsample, mVertexShaderFullscreen));
379+
CHKERR(glAttachShader(mShaderProgramDownsample, mFragmentShaderDownsample));
380+
CHKERR(glLinkProgram(mShaderProgramDownsample));
381+
if (checkProgramStatus(mShaderProgramDownsample)) {
382+
return 1;
383+
}
370384
CHKERR(glGenVertexArrays(1, &mVertexArray));
371385

372386
CHKERR(glGenVertexArrays(1, &VAO_texture));
@@ -399,6 +413,9 @@ void GPUDisplayBackendOpenGL::ExitBackendA()
399413
CHKERR(glDeleteProgram(mShaderProgramText));
400414
CHKERR(glDeleteShader(mFragmentShaderText));
401415
CHKERR(glDeleteProgram(mShaderProgramTexture));
416+
CHKERR(glDeleteProgram(mShaderProgramDownsample));
417+
CHKERR(glDeleteShader(mVertexShaderFullscreen));
418+
CHKERR(glDeleteShader(mFragmentShaderDownsample));
402419
CHKERR(glDeleteShader(mVertexShaderTexture));
403420
CHKERR(glDeleteShader(mFragmentShaderTexture));
404421

@@ -548,8 +565,10 @@ void GPUDisplayBackendOpenGL::finishDraw(bool doScreenshot, bool toMixBuffer, fl
548565
setFrameBuffer(mDownsampleFactor != 1 ? mOffscreenBuffer.fb_id : 0);
549566
mixImages(includeMixImage);
550567
}
551-
if (mDownsampleFactor != 1 && !toMixBuffer) {
568+
if (mDownsampleFactor == 2 && !toMixBuffer) { // The linear blit is only exact for factor 2
552569
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, 0, 0, 0, mRenderWidth, mRenderHeight, 0, 0, mScreenWidth, mScreenHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR));
570+
} else if (mDownsampleFactor != 1 && !toMixBuffer) {
571+
drawDownsample(mOffscreenBuffer.fbCol_id, 0, mScreenWidth, mScreenHeight, mDownsampleFactor);
553572
}
554573

555574
if (doScreenshot && !toMixBuffer) {
@@ -565,7 +584,12 @@ void GPUDisplayBackendOpenGL::readImageToPixels()
565584
GLfb tmpBuffer;
566585
if (mDisplay->cfgR().drawQualityDownsampleFSAA && mDisplay->cfgR().screenshotScaleFactor != 1) {
567586
createFB(tmpBuffer, false, true, false, width, height);
568-
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, tmpBuffer.fb_id, 0, 0, mRenderWidth, mRenderHeight, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR));
587+
const int32_t factor = mRenderWidth / width;
588+
if (factor > 2) {
589+
drawDownsample(mOffscreenBuffer.fbCol_id, tmpBuffer.fb_id, width, height, factor);
590+
} else {
591+
CHKERR(glBlitNamedFramebuffer(mOffscreenBuffer.fb_id, tmpBuffer.fb_id, 0, 0, mRenderWidth, mRenderHeight, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_LINEAR));
592+
}
569593
}
570594
setFrameBuffer(tmpBuffer.created ? tmpBuffer.fb_id : (scaleFactor != 1 ? mOffscreenBuffer.fb_id : 0));
571595
CHKERR(glPixelStorei(GL_PACK_ALIGNMENT, 1));
@@ -611,6 +635,25 @@ void GPUDisplayBackendOpenGL::finishText()
611635
}
612636
}
613637

638+
void GPUDisplayBackendOpenGL::drawDownsample(uint32_t srcTexture, uint32_t dstFramebuffer, uint32_t width, uint32_t height, int32_t factor)
639+
{
640+
setFrameBuffer(dstFramebuffer);
641+
CHKERR(glViewport(0, 0, width, height));
642+
CHKERR(glDisable(GL_DEPTH_TEST));
643+
CHKERR(glDisable(GL_BLEND));
644+
CHKERR(glUseProgram(mShaderProgramDownsample));
645+
CHKERR(glUniform1i(UNIFORM_LOCATION_COLOR, factor));
646+
CHKERR(glActiveTexture(GL_TEXTURE0));
647+
CHKERR(glBindTexture(GL_TEXTURE_2D, srcTexture));
648+
CHKERR(glBindVertexArray(VAO_texture)); // Any VAO, the full-screen triangle has no vertex input
649+
CHKERR(glDrawArrays(GL_TRIANGLES, 0, 3));
650+
CHKERR(glBindVertexArray(0));
651+
CHKERR(glBindTexture(GL_TEXTURE_2D, 0));
652+
CHKERR(glUseProgram(0));
653+
CHKERR(glEnable(GL_BLEND));
654+
setDepthBuffer();
655+
}
656+
614657
void GPUDisplayBackendOpenGL::mixImages(float mixSlaveImage)
615658
{
616659
hmm_mat4 proj = HMM_Orthographic(0.f, mRenderWidth, 0.f, mRenderHeight, -1.f, 1.f);
@@ -821,7 +864,7 @@ void GPUDisplayBackendOpenGL::updateRenderer(bool withScreenshot)
821864
createFB(mOffscreenBufferMSAA, false, true, true, mRenderWidth, mRenderHeight);
822865
}
823866
if (mDownsampleFactor != 1) {
824-
createFB(mOffscreenBuffer, false, true, false, mRenderWidth, mRenderHeight);
867+
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
825868
}
826869
createFB(mMixBuffer, true, true, false, mRenderWidth, mRenderHeight);
827870
setQuality();

‎GPU/GPUTracking/display/backend/GPUDisplayBackendOpenGL.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class GPUDisplayBackendOpenGL : public GPUDisplayBackend
6565
void prepareText() override;
6666
void finishText() override;
6767
void mixImages(float mixSlaveImage);
68+
void drawDownsample(uint32_t srcTexture, uint32_t dstFramebuffer, uint32_t width, uint32_t height, int32_t factor); // Exact box filter (fragmentDownsample.frag) for FSAA factors other than 2
6869
void pointSizeFactor(float factor) override;
6970
void lineWidthFactor(float factor) override;
7071
size_t needMultiVBO() override { return 0x100000000ll; }
@@ -95,6 +96,8 @@ class GPUDisplayBackendOpenGL : public GPUDisplayBackend
9596
uint32_t mVertexShaderPassthrough;
9697
uint32_t mFragmentShaderTexture;
9798
uint32_t mFragmentShaderText;
99+
uint32_t mVertexShaderFullscreen;
100+
uint32_t mFragmentShaderDownsample;
98101
uint32_t mGeometryShader;
99102
uint32_t mShaderProgram;
100103
uint32_t mShaderProgramSmoothPoint; // Points with fragmentSmoothPoint.frag, for smoothPoints in the core profile (no GL_POINT_SMOOTH)
@@ -103,6 +106,7 @@ class GPUDisplayBackendOpenGL : public GPUDisplayBackend
103106
bool mUseSmoothLineShader = false;
104107
uint32_t mShaderProgramText;
105108
uint32_t mShaderProgramTexture;
109+
uint32_t mShaderProgramDownsample;
106110
uint32_t mShaderProgramField;
107111
uint32_t mVertexArray;
108112

0 commit comments

Comments
 (0)