From 7ebe4e5ac18c53a7da7f42b116d2c2a368207f19 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 14 Jul 2020 17:52:40 +0100 Subject: [PATCH] Add test that GL state isn't trashed by initial contents or overlay --- util/test/demos/demos.vcxproj | 1 + util/test/demos/demos.vcxproj.filters | 3 + util/test/demos/gl/gl_state_trashing.cpp | 192 +++++++++++++++++++++++ util/test/tests/GL/GL_State_Trashing.py | 48 ++++++ 4 files changed, 244 insertions(+) create mode 100644 util/test/demos/gl/gl_state_trashing.cpp create mode 100644 util/test/tests/GL/GL_State_Trashing.py diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index c25f3b25a..dc9c704c1 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -239,6 +239,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 149a872f3..e2152fcd8 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -529,6 +529,9 @@ D3D11\demos + + OpenGL\demos + diff --git a/util/test/demos/gl/gl_state_trashing.cpp b/util/test/demos/gl/gl_state_trashing.cpp new file mode 100644 index 000000000..10961eceb --- /dev/null +++ b/util/test/demos/gl/gl_state_trashing.cpp @@ -0,0 +1,192 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2020 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "gl_test.h" + +RD_TEST(GL_State_Trashing, OpenGLGraphicsTest) +{ + static constexpr const char *Description = + "Ensures that implicit shadowed GL state isn't trashed by initial states or capture overlay."; + + std::string pixel = R"EOSHADER( +#version 420 core + +#define v2f v2f_block \ +{ \ + vec4 pos; \ + vec4 col; \ + vec4 uv; \ +} + +in v2f vertIn; + +layout(location = 0, index = 0) out vec4 Color; + +layout(binding = 0, std140) uniform constsbuf +{ + vec4 tint; +}; + +uniform vec4 tint2; + +void main() +{ + Color = vertIn.col * tint * tint2; +} + +)EOSHADER"; + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + GLuint vao = MakeVAO(); + // only time we bind the VAO, to ensure VAO state isn't trashed + glBindVertexArray(vao); + + GLuint vb = MakeBuffer(); + // only time we bind the array buffer + glBindBuffer(GL_ARRAY_BUFFER, vb); + glBufferStorage(GL_ARRAY_BUFFER, sizeof(DefaultTri), NULL, GL_DYNAMIC_STORAGE_BIT); + + GLuint ubo = MakeBuffer(); + // only time we bind the uniform buffer + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + glBufferStorage(GL_UNIFORM_BUFFER, sizeof(DefaultTri), NULL, GL_DYNAMIC_STORAGE_BIT); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, ubo); + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + + GLuint program = MakeProgram(GLDefaultVertex, pixel); + glUseProgram(program); + + GLint loc = glGetUniformLocation(program, "tint2"); + + uint32_t empty[1024] = {}; + + GLuint fbo = MakeFBO(); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + // create some things to force different types of initial states + GLuint texs[] = {MakeTexture(), MakeTexture(), MakeTexture()}; + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texs[0]); + glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGB16F, screenWidth, screenHeight, + false); + + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[1]); + glTexImage3DMultisample(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 4, GL_DEPTH_COMPONENT24, screenWidth, + screenHeight, 6, false); + + glBindTexture(GL_TEXTURE_3D, texs[2]); + glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA16F, 64, 48, 16, 0, GL_RGBA, GL_FLOAT, NULL); + + GLuint samp = 0; + glGenSamplers(1, &samp); + + GLuint pipe = MakePipeline(); + GLuint sepprog = MakeProgram("", GLDefaultPixel); + + // force things to be dirty + for(int i = 0; i < 100; i++) + { + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(DefaultTri), DefaultTri); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DefaultTri), DefaultTri); + + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texs[0], 0); + glFramebufferTextureLayer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, texs[1], 0, 0); + + glUseProgramStages(pipe, GL_FRAGMENT_SHADER_BIT, sepprog); + + glSamplerParameterf(samp, GL_TEXTURE_LOD_BIAS, 0.0f); + + glEnableVertexAttribArray(0); + } + + while(Running()) + { + // forcibly reference all objects to ensure we prepare AND serialise their initial contents + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texs[0]); + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE_ARRAY, texs[1]); + glBindTexture(GL_TEXTURE_3D, texs[2]); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glBindProgramPipeline(pipe); + glBindProgramPipeline(0); + + glBindSampler(6, samp); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + float col[] = {0.2f, 0.2f, 0.2f, 1.0f}; + glClearBufferfv(GL_COLOR, 0, col); + + glViewport(0, 0, GLsizei(screenWidth), GLsizei(screenHeight)); + + // configure the VAO. If state tracking has been corrupted this won't modify the right VAO + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(0)); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), (void *)(sizeof(Vec3f))); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(DefaultA2V), + (void *)(sizeof(Vec3f) + sizeof(Vec4f))); + + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); + glEnableVertexAttribArray(2); + + // upload the data to the implicit buffer binding - same thing as above this won't modify the + // right buffer. + Vec4f tint = Vec4f(1.0f, 1.0f, 1.0f, 1.0f); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(DefaultTri), DefaultTri); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(Vec4f), &tint); + + // set the bare uniform + glUniform4f(loc, 1.0f, 1.0f, 1.0f, 1.0f); + + glDrawArrays(GL_TRIANGLES, 0, 3); + + // trash everything so we don't get the state saved as initial contents + glUniform4f(loc, 0.0f, 0.0f, 0.0f, 0.0f); + + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(DefaultTri), empty); + glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(DefaultTri), empty); + + glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 64, (void *)(0)); + glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 64, (void *)(0)); + glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, 64, (void *)(0)); + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); + glDisableVertexAttribArray(2); + + Present(); + } + + glDeleteSamplers(1, &samp); + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/tests/GL/GL_State_Trashing.py b/util/test/tests/GL/GL_State_Trashing.py new file mode 100644 index 000000000..c5b6af78f --- /dev/null +++ b/util/test/tests/GL/GL_State_Trashing.py @@ -0,0 +1,48 @@ +import renderdoc as rd +import rdtest + + +class GL_State_Trashing(rdtest.TestCase): + demos_test_name = 'GL_State_Trashing' + + def check_capture(self): + last_draw: rd.DrawcallDescription = self.get_last_draw() + + self.controller.SetFrameEvent(last_draw.eventId, True) + + self.check_triangle(out=last_draw.copyDestination) + + draw = self.find_draw("Draw") + + self.controller.SetFrameEvent(draw.eventId, False) + + postvs_data = self.get_postvs(draw, rd.MeshDataStage.VSOut, 0, draw.numIndices) + + postvs_ref = { + 0: { + 'vtx': 0, + 'idx': 0, + 'gl_Position': [-0.5, -0.5, 0.0, 1.0], + 'v2f_block.pos': [-0.5, -0.5, 0.0, 1.0], + 'v2f_block.col': [0.0, 1.0, 0.0, 1.0], + 'v2f_block.uv': [0.0, 0.0, 0.0, 1.0], + }, + 1: { + 'vtx': 1, + 'idx': 1, + 'gl_Position': [0.0, 0.5, 0.0, 1.0], + 'v2f_block.pos': [0.0, 0.5, 0.0, 1.0], + 'v2f_block.col': [0.0, 1.0, 0.0, 1.0], + 'v2f_block.uv': [0.0, 1.0, 0.0, 1.0], + }, + 2: { + 'vtx': 2, + 'idx': 2, + 'gl_Position': [0.5, -0.5, 0.0, 1.0], + 'v2f_block.pos': [0.5, -0.5, 0.0, 1.0], + 'v2f_block.col': [0.0, 1.0, 0.0, 1.0], + 'v2f_block.uv': [1.0, 0.0, 0.0, 1.0], + }, + } + + self.check_mesh_data(postvs_ref, postvs_data)