From 59eebd09f5980e42ae53b886b2c321605dc4e1b2 Mon Sep 17 00:00:00 2001 From: assiduous Date: Wed, 18 Dec 2019 00:19:10 -0800 Subject: Implemented staging textures in OpenGL backend; enabled draw command reference in GL test --- UnitTests/DiligentCoreAPITest/CMakeLists.txt | 14 ++- .../include/GL/TestingEnvironmentGL.h | 16 ++++ .../include/GL/TestingSwapChainGL.h | 6 ++ .../src/GL/DrawCommandRefenceGL.cpp | 78 ++++++++++++++++ .../src/GL/TestingEnvironmentGL.cpp | 93 ++++++++++++++++++- .../src/GL/TestingSwapChainGL.cpp | 100 ++++++++++++++++++++- .../DiligentCoreAPITest/src/TestingEnvironment.cpp | 3 +- UnitTests/DiligentCoreAPITest/src/main.cpp | 1 + 8 files changed, 304 insertions(+), 7 deletions(-) (limited to 'UnitTests') diff --git a/UnitTests/DiligentCoreAPITest/CMakeLists.txt b/UnitTests/DiligentCoreAPITest/CMakeLists.txt index 9232aefd..f0c2673c 100644 --- a/UnitTests/DiligentCoreAPITest/CMakeLists.txt +++ b/UnitTests/DiligentCoreAPITest/CMakeLists.txt @@ -88,10 +88,18 @@ endif() if(GL_SUPPORTED OR GLES_SUPPORTED) target_link_libraries(DiligentCoreAPITest PRIVATE Diligent-HLSL2GLSLConverterLib) -endif() -if(GL_SUPPORTED) - target_link_libraries(DiligentCoreAPITest PRIVATE glew-static) + if(PLATFORM_WIN32) + target_link_libraries(DiligentCoreAPITest PRIVATE glew-static opengl32.lib) + elseif(PLATFORM_LINUX) + target_link_libraries(DiligentCoreAPITest PRIVATE glew-static) + elseif(PLATFORM_MACOS) + find_package(OpenGL REQUIRED) + target_link_libraries(DiligentCoreAPITest PRIVATE glew-static ${OPENGL_LIBRARY}) + else() + message(FATAL_ERROR "Unsupported platform") + endif() + endif() if(VULKAN_SUPPORTED) diff --git a/UnitTests/DiligentCoreAPITest/include/GL/TestingEnvironmentGL.h b/UnitTests/DiligentCoreAPITest/include/GL/TestingEnvironmentGL.h index 981d6a1f..306e1d8f 100644 --- a/UnitTests/DiligentCoreAPITest/include/GL/TestingEnvironmentGL.h +++ b/UnitTests/DiligentCoreAPITest/include/GL/TestingEnvironmentGL.h @@ -23,6 +23,15 @@ #pragma once +#ifndef GLEW_STATIC +# define GLEW_STATIC // Must be defined to use static version of glew +#endif +#ifndef GLEW_NO_GLU +# define GLEW_NO_GLU +#endif + +#include "GL/glew.h" + #include "TestingEnvironment.h" namespace Diligent @@ -35,10 +44,17 @@ class TestingEnvironmentGL final : public TestingEnvironment { public: TestingEnvironmentGL(DeviceType deviceType, ADAPTER_TYPE AdapterType, const SwapChainDesc& SCDesc); + ~TestingEnvironmentGL(); static TestingEnvironmentGL* GetInstance() { return ValidatedCast(TestingEnvironment::GetInstance()); } + GLuint CompileGLShader(const char* Source, GLenum ShaderType); + GLuint LinkProgram(GLuint Shaders[], GLuint NumShaders); + + GLuint GetDummyVAO() { return m_DummyVAO; } + private: + GLuint m_DummyVAO = 0; }; } // namespace Testing diff --git a/UnitTests/DiligentCoreAPITest/include/GL/TestingSwapChainGL.h b/UnitTests/DiligentCoreAPITest/include/GL/TestingSwapChainGL.h index 3a5058e8..fa6c3c37 100644 --- a/UnitTests/DiligentCoreAPITest/include/GL/TestingSwapChainGL.h +++ b/UnitTests/DiligentCoreAPITest/include/GL/TestingSwapChainGL.h @@ -37,10 +37,16 @@ public: IRenderDevice* pDevice, IDeviceContext* pContext, const SwapChainDesc& SCDesc); + ~TestingSwapChainGL(); virtual void TakeSnapshot() override final; + void BindFramebuffer(); + private: + GLuint m_RenderTarget = 0; + GLuint m_DepthBuffer = 0; + GLuint m_FBO = 0; }; } // namespace Testing diff --git a/UnitTests/DiligentCoreAPITest/src/GL/DrawCommandRefenceGL.cpp b/UnitTests/DiligentCoreAPITest/src/GL/DrawCommandRefenceGL.cpp index 18acef04..8f9e748e 100644 --- a/UnitTests/DiligentCoreAPITest/src/GL/DrawCommandRefenceGL.cpp +++ b/UnitTests/DiligentCoreAPITest/src/GL/DrawCommandRefenceGL.cpp @@ -22,6 +22,7 @@ */ #include "GL/TestingEnvironmentGL.h" +#include "GL/TestingSwapChainGL.h" namespace Diligent { @@ -30,13 +31,90 @@ namespace Testing { static const char* VSSource = R"( +#version 420 core + +#ifndef GL_ES +out gl_PerVertex +{ + vec4 gl_Position; +}; +#endif + +layout(location = 0) out vec3 out_Color; + +void main() +{ + vec4 Pos[4]; + Pos[0] = vec4(-0.5, -0.5, 0.0, 1.0); + Pos[1] = vec4(-0.5, +0.5, 0.0, 1.0); + Pos[2] = vec4(+0.5, -0.5, 0.0, 1.0); + Pos[3] = vec4(+0.5, +0.5, 0.0, 1.0); + + vec3 Col[4]; + Col[0] = vec3(1.0, 0.0, 0.0); + Col[1] = vec3(0.0, 1.0, 0.0); + Col[2] = vec3(0.0, 0.0, 1.0); + Col[3] = vec3(1.0, 1.0, 1.0); + + gl_Position = Pos[gl_VertexID]; + out_Color = Col[gl_VertexID]; +} )"; static const char* PSSource = R"( +#version 420 core + +layout(location = 0) in vec3 in_Color; +layout(location = 0) out vec4 out_Color; + +void main() +{ + out_Color = vec4(in_Color, 1.0); +} )"; void RenderDrawCommandRefenceGL(ISwapChain* pSwapChain) { + auto* pEnv = TestingEnvironmentGL::GetInstance(); + auto* pContext = pEnv->GetDeviceContext(); + auto* pTestingSwapChainGL = ValidatedCast(pSwapChain); + + const auto& SCDesc = pTestingSwapChainGL->GetDesc(); + + GLuint glShaders[2] = {}; + glShaders[0] = pEnv->CompileGLShader(VSSource, GL_VERTEX_SHADER); + ASSERT_NE(glShaders[0], 0u); + glShaders[1] = pEnv->CompileGLShader(PSSource, GL_FRAGMENT_SHADER); + ASSERT_NE(glShaders[1], 0u); + auto glProg = pEnv->LinkProgram(glShaders, 2); + ASSERT_NE(glProg, 0u); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDisable(GL_CULL_FACE); + if (glPolygonMode != nullptr) + { + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + } + pTestingSwapChainGL->BindFramebuffer(); + glViewport(0, 0, SCDesc.Width, SCDesc.Height); + glUseProgram(glProg); + glBindVertexArray(pEnv->GetDummyVAO()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glUseProgram(0); + + // Make sure Diligent Engine will reset all GL states + pContext->InvalidateState(); + + for(int i = 0; i < _countof(glShaders); ++i) + { + if (glShaders[i] != 0) + glDeleteShader(glShaders[i]); + } + if (glProg != 0) + glDeleteProgram(glProg); } } // namespace Testing diff --git a/UnitTests/DiligentCoreAPITest/src/GL/TestingEnvironmentGL.cpp b/UnitTests/DiligentCoreAPITest/src/GL/TestingEnvironmentGL.cpp index 538cc051..a78318cb 100644 --- a/UnitTests/DiligentCoreAPITest/src/GL/TestingEnvironmentGL.cpp +++ b/UnitTests/DiligentCoreAPITest/src/GL/TestingEnvironmentGL.cpp @@ -37,15 +37,106 @@ void CreateTestingSwapChainGL(IRenderDevice* pDevice, TestingEnvironmentGL::TestingEnvironmentGL(DeviceType deviceType, ADAPTER_TYPE AdapterType, const SwapChainDesc& SCDesc) : TestingEnvironment{deviceType, AdapterType, SCDesc} { + // Initialize GLEW + auto err = glewInit(); + if (GLEW_OK != err) + LOG_ERROR_AND_THROW("Failed to initialize GLEW"); + if (m_pSwapChain == nullptr) { CreateTestingSwapChainGL(m_pDevice, m_pDeviceContext, SCDesc, &m_pSwapChain); } + + glGenVertexArrays(1, &m_DummyVAO); +} + +TestingEnvironmentGL::~TestingEnvironmentGL() +{ + glDeleteVertexArrays(1, &m_DummyVAO); +} + +GLuint TestingEnvironmentGL::CompileGLShader(const char* Source, GLenum ShaderType) +{ + GLuint glShader = glCreateShader(ShaderType); + + const char* ShaderStrings[] = {Source}; + GLint Lenghts[] = {static_cast(strlen(Source))}; + + // Provide source strings (the strings will be saved in internal OpenGL memory) + glShaderSource(glShader, _countof(ShaderStrings), ShaderStrings, Lenghts); + // When the shader is compiled, it will be compiled as if all of the given strings were concatenated end-to-end. + glCompileShader(glShader); + GLint compiled = GL_FALSE; + // Get compilation status + glGetShaderiv(glShader, GL_COMPILE_STATUS, &compiled); + if (!compiled) + { + int infoLogLen = 0; + // The function glGetShaderiv() tells how many bytes to allocate; the length includes the NULL terminator. + glGetShaderiv(glShader, GL_INFO_LOG_LENGTH, &infoLogLen); + + std::vector infoLog(infoLogLen); + if (infoLogLen > 0) + { + int charsWritten = 0; + // Get the log. infoLogLen is the size of infoLog. This tells OpenGL how many bytes at maximum it will write + // charsWritten is a return value, specifying how many bytes it actually wrote. One may pass NULL if he + // doesn't care + glGetShaderInfoLog(glShader, infoLogLen, &charsWritten, infoLog.data()); + VERIFY(charsWritten == infoLogLen - 1, "Unexpected info log length"); + LOG_ERROR("Failed to compile GL shader\n", infoLog.data()); + } + } + + return glShader; +} + +GLuint TestingEnvironmentGL::LinkProgram(GLuint Shaders[], GLuint NumShaders) +{ + auto glProg = glCreateProgram(); + + for (Uint32 i = 0; i < NumShaders; ++i) + { + glAttachShader(glProg, Shaders[i]); + VERIFY_EXPR(glGetError() == GL_NO_ERROR); + } + + glLinkProgram(glProg); + int IsLinked = GL_FALSE; + glGetProgramiv(glProg, GL_LINK_STATUS, &IsLinked); + if (!IsLinked) + { + int LengthWithNull = 0, Length = 0; + // Notice that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. + // The length of the info log includes a null terminator. + glGetProgramiv(glProg, GL_INFO_LOG_LENGTH, &LengthWithNull); + + // The maxLength includes the NULL character + std::vector shaderProgramInfoLog(LengthWithNull); + + // Notice that glGetProgramInfoLog is used, not glGetShaderInfoLog. + glGetProgramInfoLog(glProg, LengthWithNull, &Length, shaderProgramInfoLog.data()); + VERIFY(Length == LengthWithNull - 1, "Incorrect program info log len"); + LOG_ERROR_MESSAGE("Failed to link shader program:\n", shaderProgramInfoLog.data(), '\n'); + } + + for (Uint32 i = 0; i < NumShaders; ++i) + { + glDetachShader(glProg, Shaders[i]); + } + return glProg; } TestingEnvironment* CreateTestingEnvironmentGL(DeviceType deviceType, ADAPTER_TYPE AdapterType, const SwapChainDesc& SCDesc) { - return new TestingEnvironmentGL{deviceType, AdapterType, SCDesc}; + try + { + return new TestingEnvironmentGL{deviceType, AdapterType, SCDesc}; + } + catch (...) + { + return nullptr; + } } } // namespace Testing diff --git a/UnitTests/DiligentCoreAPITest/src/GL/TestingSwapChainGL.cpp b/UnitTests/DiligentCoreAPITest/src/GL/TestingSwapChainGL.cpp index b5e36936..9c3cea64 100644 --- a/UnitTests/DiligentCoreAPITest/src/GL/TestingSwapChainGL.cpp +++ b/UnitTests/DiligentCoreAPITest/src/GL/TestingSwapChainGL.cpp @@ -21,6 +21,7 @@ * of the possibility of such damages. */ +#include "GL/TestingEnvironmentGL.h" #include "GL/TestingSwapChainGL.h" namespace Diligent @@ -41,10 +42,98 @@ TestingSwapChainGL::TestingSwapChainGL(IReferenceCounters* pRefCounters, SCDesc // } { + { + glGenTextures(1, &m_RenderTarget); + if (glGetError() != GL_NO_ERROR) + LOG_ERROR_AND_THROW("Failed to create render target texture"); + + GLenum RenderTargetFmt = 0; + switch (m_SwapChainDesc.ColorBufferFormat) + { + case TEX_FORMAT_RGBA8_UNORM: + RenderTargetFmt = GL_RGBA8; + break; + + default: + UNSUPPORTED("Texture format ", GetTextureFormatAttribs(m_SwapChainDesc.ColorBufferFormat).Name, " is not a supported color buffer format"); + } + + glBindTexture(GL_TEXTURE_2D, m_RenderTarget); + // levels format width height + glTexStorage2D(GL_TEXTURE_2D, 1, RenderTargetFmt, m_SwapChainDesc.Width, m_SwapChainDesc.Height); + if (glGetError() != GL_NO_ERROR) + LOG_ERROR_AND_THROW("Failed to allocate render target texture"); + } + + + { + glGenTextures(1, &m_DepthBuffer); + if (glGetError() != GL_NO_ERROR) + LOG_ERROR_AND_THROW("Failed to create depth texture"); + + GLenum DepthBufferFmt = 0; + switch (m_SwapChainDesc.DepthBufferFormat) + { + case TEX_FORMAT_D32_FLOAT: + DepthBufferFmt = GL_DEPTH_COMPONENT32F; + break; + + default: + UNSUPPORTED("Texture format ", GetTextureFormatAttribs(m_SwapChainDesc.DepthBufferFormat).Name, " is not a supported depth buffer format"); + } + + glBindTexture(GL_TEXTURE_2D, m_DepthBuffer); + // levels format width height + glTexStorage2D(GL_TEXTURE_2D, 1, DepthBufferFmt, m_SwapChainDesc.Width, m_SwapChainDesc.Height); + if (glGetError() != GL_NO_ERROR) + LOG_ERROR_AND_THROW("Failed to allocate render target texture"); + } + + { + glGenFramebuffers(1, &m_FBO); + if (glGetError() != GL_NO_ERROR) + LOG_ERROR_AND_THROW("Failed to create FBO"); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_RenderTarget, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_RenderTarget, 0); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthBuffer, 0); + glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, m_DepthBuffer, 0); + static const GLenum DrawBuffers[] = {GL_COLOR_ATTACHMENT0}; + glDrawBuffers(1, DrawBuffers); + GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (Status != GL_FRAMEBUFFER_COMPLETE) + LOG_ERROR_AND_THROW("FBO is incomplete"); + } + + // Make sure Diligent Engine will reset all GL states + pContext->InvalidateState(); +} + +void TestingSwapChainGL::BindFramebuffer() +{ + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_FBO); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO); +} + +TestingSwapChainGL::~TestingSwapChainGL() +{ + if (m_RenderTarget != 0) + glDeleteTextures(1, &m_RenderTarget); + if (m_DepthBuffer != 0) + glDeleteTextures(1, &m_DepthBuffer); + if (m_FBO != 0) + glDeleteFramebuffers(1, &m_FBO); } void TestingSwapChainGL::TakeSnapshot() { + m_ReferenceDataPitch = m_SwapChainDesc.Width * 4; + m_ReferenceData.resize(m_SwapChainDesc.Height * m_ReferenceDataPitch); + glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_FBO); + glReadPixels(0, 0, m_SwapChainDesc.Width, m_SwapChainDesc.Height, GL_RGBA, GL_UNSIGNED_BYTE, m_ReferenceData.data()); } void CreateTestingSwapChainGL(IRenderDevice* pDevice, @@ -52,8 +141,15 @@ void CreateTestingSwapChainGL(IRenderDevice* pDevice, const SwapChainDesc& SCDesc, ISwapChain** ppSwapChain) { - TestingSwapChainGL* pTestingSC(MakeNewRCObj()(pDevice, pContext, SCDesc)); - pTestingSC->QueryInterface(IID_SwapChain, reinterpret_cast(ppSwapChain)); + try + { + TestingSwapChainGL* pTestingSC(MakeNewRCObj()(pDevice, pContext, SCDesc)); + pTestingSC->QueryInterface(IID_SwapChain, reinterpret_cast(ppSwapChain)); + } + catch (...) + { + *ppSwapChain = nullptr; + } } } // namespace Testing diff --git a/UnitTests/DiligentCoreAPITest/src/TestingEnvironment.cpp b/UnitTests/DiligentCoreAPITest/src/TestingEnvironment.cpp index e187fc3e..dca742a8 100644 --- a/UnitTests/DiligentCoreAPITest/src/TestingEnvironment.cpp +++ b/UnitTests/DiligentCoreAPITest/src/TestingEnvironment.cpp @@ -274,8 +274,9 @@ TestingEnvironment::TestingEnvironment(DeviceType deviceType, ADAPTER_TYPE Adapt NumDeferredCtx = 0; } ppContexts.resize(1 + NumDeferredCtx); + RefCntAutoPtr pSwapChain; // We will use testing swap chain instead pFactoryOpenGL->CreateDeviceAndSwapChainGL( - CreateInfo, &m_pDevice, ppContexts.data(), SCDesc, &m_pSwapChain); + CreateInfo, &m_pDevice, ppContexts.data(), SCDesc, &pSwapChain); } break; #endif diff --git a/UnitTests/DiligentCoreAPITest/src/main.cpp b/UnitTests/DiligentCoreAPITest/src/main.cpp index 4db55c5a..bacaca9f 100644 --- a/UnitTests/DiligentCoreAPITest/src/main.cpp +++ b/UnitTests/DiligentCoreAPITest/src/main.cpp @@ -171,5 +171,6 @@ int main(int argc, char** argv) ::testing::AddGlobalTestEnvironment(pEnv); auto ret_val = RUN_ALL_TESTS(); + std::cout << "\n\n\n"; return ret_val; } -- cgit v1.2.3