diff --git a/util/test/demos/CMakeLists.txt b/util/test/demos/CMakeLists.txt index 486934920..909f7b1dd 100644 --- a/util/test/demos/CMakeLists.txt +++ b/util/test/demos/CMakeLists.txt @@ -84,6 +84,7 @@ set(OPENGL_SRC gl/gl_parameter_zoo.cpp gl/gl_per_type_tex_units.cpp gl/gl_queries_in_use.cpp + gl/gl_renderbuffer_zoo.cpp gl/gl_resource_lifetimes.cpp gl/gl_runtime_bind_prog_to_pipe.cpp gl/gl_separable_geometry_shader.cpp diff --git a/util/test/demos/demos.vcxproj b/util/test/demos/demos.vcxproj index 6ddaa2a09..7eaba3c1f 100644 --- a/util/test/demos/demos.vcxproj +++ b/util/test/demos/demos.vcxproj @@ -245,6 +245,7 @@ + diff --git a/util/test/demos/demos.vcxproj.filters b/util/test/demos/demos.vcxproj.filters index 6a83f9b77..456ca676e 100644 --- a/util/test/demos/demos.vcxproj.filters +++ b/util/test/demos/demos.vcxproj.filters @@ -592,6 +592,9 @@ Vulkan\demos + + OpenGL\demos + diff --git a/util/test/demos/gl/gl_renderbuffer_zoo.cpp b/util/test/demos/gl/gl_renderbuffer_zoo.cpp new file mode 100644 index 000000000..eb7c5ab79 --- /dev/null +++ b/util/test/demos/gl/gl_renderbuffer_zoo.cpp @@ -0,0 +1,169 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 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_Renderbuffer_Zoo, OpenGLGraphicsTest) +{ + static constexpr const char *Description = + "Tests different types of renderbuffers to ensure they work correctly in normal texture " + "operations"; + + int main() + { + // initialise, create window, create context, etc + if(!Init()) + return 3; + + GLuint vao = MakeVAO(); + glBindVertexArray(vao); + + const DefaultA2V Tri[3] = { + {Vec3f(-0.5f, -0.5f, 0.5f), Vec4f(0.2f, 0.75f, 0.2f, 1.0f), Vec2f(0.0f, 0.0f)}, + {Vec3f(0.0f, 0.5f, 0.5f), Vec4f(0.2f, 0.75f, 0.2f, 1.0f), Vec2f(0.0f, 1.0f)}, + {Vec3f(0.5f, -0.5f, 0.5f), Vec4f(0.2f, 0.75f, 0.2f, 1.0f), Vec2f(1.0f, 0.0f)}, + }; + + GLuint vb = MakeBuffer(); + glBindBuffer(GL_ARRAY_BUFFER, vb); + glBufferData(GL_ARRAY_BUFFER, sizeof(Tri), Tri, GL_STATIC_DRAW); + + ConfigureDefaultVAO(); + + GLuint program = MakeProgram(GLDefaultVertex, GLDefaultPixel); + + GLuint fbo = MakeFBO(); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + GLenum db = GL_COLOR_ATTACHMENT0; + glDrawBuffers(1, &db); + + GLuint rbs[9] = {}; + glGenRenderbuffers(ARRAY_COUNT(rbs), rbs); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[0]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, 512, 512); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[1]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, 512, 512); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[2]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA16F, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[3]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[4]); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[5]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_RGBA16F, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[6]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 1, GL_RGBA16F, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[7]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 0, GL_RGBA16F, 640, 480); + + glBindRenderbuffer(GL_RENDERBUFFER, rbs[8]); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, 640, 480); + + float col[] = {0.2f, 0.2f, 0.2f, 1.0f}; + while(Running()) + { + glBindVertexArray(vao); + glUseProgram(program); + + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + glDisable(GL_DEPTH_TEST); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[0]); + glViewport(0, 0, 512, 512); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[1]); + glViewport(0, 0, 512, 512); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[2]); + glViewport(0, 0, 640, 480); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glEnable(GL_DEPTH_TEST); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbs[3]); + + glClearBufferfv(GL_COLOR, 0, col); + glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.9f, 0); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbs[4]); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + + glClearBufferfv(GL_COLOR, 0, col); + glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.9f, 0); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glDisable(GL_DEPTH_TEST); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[5]); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[6]); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[7]); + + glClearBufferfv(GL_COLOR, 0, col); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glEnable(GL_DEPTH_TEST); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbs[5]); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbs[8]); + + glClearBufferfv(GL_COLOR, 0, col); + glClearBufferfi(GL_DEPTH_STENCIL, 0, 0.9f, 0); + glDrawArrays(GL_TRIANGLES, 0, 3); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + Present(); + } + + glDeleteRenderbuffers(ARRAY_COUNT(rbs), rbs); + + return 0; + } +}; + +REGISTER_TEST(); diff --git a/util/test/rdtest/testcase.py b/util/test/rdtest/testcase.py index 3ece88517..b2efb9740 100644 --- a/util/test/rdtest/testcase.py +++ b/util/test/rdtest/testcase.py @@ -375,6 +375,8 @@ class TestCase: # Reduce epsilon for RGBA8 textures if it's not already reduced if tex_details.format.compByteWidth == 1 and eps == util.FLT_EPSILON: eps = (1.0 / 255.0) + if tex_details.format.compByteWidth == 2 and eps == util.FLT_EPSILON: + eps = (1.0 / 16384.0) picked: rd.PixelValue = self.controller.PickPixel(tex, x, y, sub, cast) diff --git a/util/test/tests/GL/GL_Renderbuffer_Zoo.py b/util/test/tests/GL/GL_Renderbuffer_Zoo.py new file mode 100644 index 000000000..0e599c435 --- /dev/null +++ b/util/test/tests/GL/GL_Renderbuffer_Zoo.py @@ -0,0 +1,98 @@ +import renderdoc as rd +import rdtest + + +class GL_Renderbuffer_Zoo(rdtest.TestCase): + demos_test_name = 'GL_Renderbuffer_Zoo' + + def check_capture(self): + draw: rd.DrawcallDescription = self.find_draw('glDraw') + + while draw is not None: + self.controller.SetFrameEvent(draw.eventId, True) + + self.check_triangle(fore=[0.2, 0.75, 0.2, 1.0]) + + pipe = self.controller.GetPipelineState() + depth = pipe.GetDepthTarget() + vp = pipe.GetViewport(0) + + id = pipe.GetOutputTargets()[0].resourceId + + mn, mx = self.controller.GetMinMax(id, rd.Subresource(), rd.CompType.Typeless) + + if not rdtest.value_compare(mn.floatValue, [0.2, 0.2, 0.2, 1.0], eps=1.0/255.0): + raise rdtest.TestFailureException( + "Minimum color values {} are not as expected".format(mn.floatValue)) + + if not rdtest.value_compare(mx.floatValue, [0.2, 0.75, 0.2, 1.0], eps=1.0/255.0): + raise rdtest.TestFailureException( + "Maximum color values {} are not as expected".format(mx.floatValue)) + + hist = self.controller.GetHistogram(id, rd.Subresource(), rd.CompType.Typeless, 0.199, 0.75, + (False, True, False, False)) + + if hist[0] == 0 or hist[-1] == 0 or any([x > 0 for x in hist[1:-1]]): + raise rdtest.TestFailureException( + "Green histogram didn't return expected values, values should have landed in first or last bucket") + + rdtest.log.success('Color Renderbuffer at draw {} is working as expected'.format(draw.eventId)) + + if depth.resourceId != rd.ResourceId(): + val = self.controller.PickPixel(depth.resourceId, int(0.5 * vp.width), int(0.5 * vp.height), + rd.Subresource(), rd.CompType.Typeless) + + if not rdtest.value_compare(val.floatValue[0], 0.75): + raise rdtest.TestFailureException( + "Picked value {} in triangle for depth doesn't match expectation".format(val)) + + mn, mx = self.controller.GetMinMax(depth.resourceId, rd.Subresource(), rd.CompType.Typeless) + hist = self.controller.GetHistogram(depth.resourceId, rd.Subresource(), + rd.CompType.Typeless, 0.75, 0.9, (True, False, False, False)) + + if not rdtest.value_compare(mn.floatValue[0], 0.75): + raise rdtest.TestFailureException( + "Minimum depth values {} are not as expected".format(mn.floatValue)) + + if not rdtest.value_compare(mx.floatValue[0], 0.9): + raise rdtest.TestFailureException( + "Maximum depth values {} are not as expected".format(mx.floatValue)) + + if hist[0] == 0 or hist[-1] == 0 or any([x > 0 for x in hist[1:-1]]): + raise rdtest.TestFailureException( + "Depth histogram didn't return expected values, values should have landed in first or last bucket") + + rdtest.log.success('Depth Renderbuffer at draw {} is working as expected'.format(draw.eventId)) + + tex_details = self.get_texture(id) + + if tex_details.msSamp > 1: + samples = [] + for i in range(tex_details.msSamp): + samples.append(self.controller.GetTextureData(id, rd.Subresource(0, 0, i))) + + for i in range(tex_details.msSamp): + for j in range(tex_details.msSamp): + if i == j: + continue + + if samples[i] == samples[j]: + save_data = rd.TextureSave() + save_data.resourceId = id + save_data.destType = rd.FileType.PNG + save_data.slice.sliceIndex = 0 + save_data.mip = 0 + + img_path0 = rdtest.get_tmp_path('sample{}.png'.format(i)) + img_path1 = rdtest.get_tmp_path('sample{}.png'.format(j)) + + save_data.sample.sampleIndex = i + self.controller.SaveTexture(save_data, img_path0) + save_data.sample.sampleIndex = j + self.controller.SaveTexture(save_data, img_path1) + + raise rdtest.TestFailureException("Two MSAA samples returned the same data", img_path0, img_path1) + + draw: rd.DrawcallDescription = self.find_draw('glDraw', draw.eventId+1) + + rdtest.log.success('All renderbuffers checked and rendered correctly')