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 --- .../GraphicsEngineOpenGL/include/BufferGLImpl.h | 1 + .../include/GLTypeConversions.h | 11 +- .../include/RenderDeviceGLImpl.h | 4 +- .../GraphicsEngineOpenGL/include/TextureBaseGL.h | 8 ++ Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp | 26 +++-- .../src/DeviceContextGLImpl.cpp | 129 ++++++++++++++++++++- .../src/Texture1DArray_OGL.cpp | 6 + .../GraphicsEngineOpenGL/src/Texture1D_OGL.cpp | 6 + .../src/Texture2DArray_OGL.cpp | 6 + .../GraphicsEngineOpenGL/src/Texture2D_OGL.cpp | 6 + .../GraphicsEngineOpenGL/src/Texture3D_OGL.cpp | 6 + .../GraphicsEngineOpenGL/src/TextureBaseGL.cpp | 72 ++++++++++-- .../src/TextureCubeArray_OGL.cpp | 6 + .../GraphicsEngineOpenGL/src/TextureCube_OGL.cpp | 6 + 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 + 22 files changed, 567 insertions(+), 37 deletions(-) diff --git a/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.h index 2747ff66..8c1e44f2 100644 --- a/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.h +++ b/Graphics/GraphicsEngineOpenGL/include/BufferGLImpl.h @@ -67,6 +67,7 @@ public: void UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 Size, const PVoid pData); void CopyData(GLContextState& CtxState, BufferGLImpl& SrcBufferGL, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size); void Map(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, PVoid& pMappedData); + void MapRange(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, Uint32 Offset, Uint32 Length, PVoid& pMappedData); void Unmap(GLContextState& CtxState); void BufferMemoryBarrier(Uint32 RequiredBarriers, class GLContextState& GLContextState); diff --git a/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.h b/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.h index 60525d6e..5ba8baaf 100644 --- a/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.h +++ b/Graphics/GraphicsEngineOpenGL/include/GLTypeConversions.h @@ -94,11 +94,11 @@ inline GLenum TypeToGLType(VALUE_TYPE Value) return GLType; } -inline GLenum UsageToGLUsage(USAGE Usage) +inline GLenum UsageToGLUsage(const BufferDesc& Desc) { // http://www.informit.com/articles/article.aspx?p=2033340&seqNum=2 // https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glBufferData.xml - switch (Usage) + switch (Desc.Usage) { // STATIC: The data store contents will be modified once and used many times. // STREAM: The data store contents will be modified once and used at MOST a few times. @@ -108,7 +108,12 @@ inline GLenum UsageToGLUsage(USAGE Usage) case USAGE_STATIC: return GL_STATIC_DRAW; case USAGE_DEFAULT: return GL_STATIC_DRAW; case USAGE_DYNAMIC: return GL_DYNAMIC_DRAW; - case USAGE_STAGING: return GL_DYNAMIC_READ; + case USAGE_STAGING: + if(Desc.CPUAccessFlags & CPU_ACCESS_READ) + return GL_STATIC_READ; + else + return GL_STATIC_COPY; + default: UNEXPECTED( "Unknow usage" ); return 0; // clang-format on } diff --git a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.h b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.h index d7d94679..1f2bf173 100644 --- a/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.h +++ b/Graphics/GraphicsEngineOpenGL/include/RenderDeviceGLImpl.h @@ -64,8 +64,8 @@ public: virtual void QueryInterface(const INTERFACE_ID& IID, IObject** ppInterface) override; /// Implementation of IRenderDevice::CreateBuffer() in OpenGL backend. - void CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, IBuffer** ppBufferLayout, bool bIsDeviceInternal); - virtual void CreateBuffer(const BufferDesc& BuffDesc, const BufferData* BuffData, IBuffer** ppBufferLayout) override final; + void CreateBuffer(const BufferDesc& BuffDesc, const BufferData* pBuffData, IBuffer** ppBuffer, bool bIsDeviceInternal); + virtual void CreateBuffer(const BufferDesc& BuffDesc, const BufferData* BuffData, IBuffer** ppBuffer) override final; /// Implementation of IRenderDevice::CreateShader() in OpenGL backend. void CreateShader(const ShaderCreateInfo& ShaderCreateInfo, IShader** ppShader, bool bIsDeviceInternal); diff --git a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.h b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.h index 132ba912..6a98d417 100644 --- a/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.h +++ b/Graphics/GraphicsEngineOpenGL/include/TextureBaseGL.h @@ -110,6 +110,13 @@ public: const Box& DstBox, const TextureSubResData& SubresData) = 0; + static Uint32 GetPBODataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint32 MipLevel); + + IBuffer* GetPBO() + { + return m_pPBO; + } + protected: virtual void CreateViewInternal(const struct TextureViewDesc& ViewDesc, class ITextureView** ppView, @@ -118,6 +125,7 @@ protected: void SetDefaultGLParameters(); GLObjectWrappers::GLTextureObj m_GlTexture; + RefCntAutoPtr m_pPBO; // For staging textures const GLenum m_BindTarget; const GLenum m_GLTexFormat; //Uint32 m_uiMapTarget; diff --git a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp index e11f1765..9c1f58e2 100644 --- a/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/BufferGLImpl.cpp @@ -54,8 +54,13 @@ static GLenum GetBufferBindTarget(const BufferDesc& Desc) #endif Target = GL_DRAW_INDIRECT_BUFFER; } - else if (Desc.Usage == USAGE_STAGING && Desc.CPUAccessFlags == CPU_ACCESS_WRITE) - Target = GL_PIXEL_UNPACK_BUFFER; + else if (Desc.Usage == USAGE_STAGING) + { + if (Desc.CPUAccessFlags == CPU_ACCESS_WRITE) + Target = GL_PIXEL_UNPACK_BUFFER; + else if (Desc.CPUAccessFlags == CPU_ACCESS_READ) + Target = GL_PIXEL_PACK_BUFFER; + } return Target; } @@ -77,7 +82,7 @@ BufferGLImpl::BufferGLImpl(IReferenceCounters* pRefCounters, }, m_GlBuffer {true }, // Create buffer immediately m_BindTarget {GetBufferBindTarget(BuffDesc) }, - m_GLUsageHint {UsageToGLUsage(BuffDesc.Usage)} + m_GLUsageHint {UsageToGLUsage(BuffDesc)} // clang-format on { if (BuffDesc.Usage == USAGE_STATIC && (pBuffData == nullptr || pBuffData->pData == nullptr)) @@ -189,7 +194,7 @@ BufferGLImpl::BufferGLImpl(IReferenceCounters* pRefCounters, // Attach to external buffer handle m_GlBuffer {true, GLObjectWrappers::GLBufferObjCreateReleaseHelper(GLHandle)}, m_BindTarget {GetBufferBindTarget(m_Desc) }, - m_GLUsageHint {UsageToGLUsage(BuffDesc.Usage)} + m_GLUsageHint {UsageToGLUsage(BuffDesc)} // clang-format on { } @@ -201,7 +206,7 @@ BufferGLImpl::~BufferGLImpl() IMPLEMENT_QUERY_INTERFACE(BufferGLImpl, IID_BufferGL, TBufferBase) -void BufferGLImpl ::UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 Size, const PVoid pData) +void BufferGLImpl::UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 Size, const PVoid pData) { BufferMemoryBarrier( GL_BUFFER_UPDATE_BARRIER_BIT, // Reads or writes to buffer objects via any OpenGL API functions that allow @@ -221,7 +226,7 @@ void BufferGLImpl ::UpdateData(GLContextState& CtxState, Uint32 Offset, Uint32 S } -void BufferGLImpl ::CopyData(GLContextState& CtxState, BufferGLImpl& SrcBufferGL, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size) +void BufferGLImpl::CopyData(GLContextState& CtxState, BufferGLImpl& SrcBufferGL, Uint32 SrcOffset, Uint32 DstOffset, Uint32 Size) { BufferMemoryBarrier( GL_BUFFER_UPDATE_BARRIER_BIT, // Reads or writes to buffer objects via any OpenGL API functions that allow @@ -247,7 +252,12 @@ void BufferGLImpl ::CopyData(GLContextState& CtxState, BufferGLImpl& SrcBufferGL CtxState.BindBuffer(GL_COPY_WRITE_BUFFER, GLObjectWrappers::GLBufferObj::Null(), ResetVAO); } -void BufferGLImpl ::Map(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, PVoid& pMappedData) +void BufferGLImpl::Map(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, PVoid& pMappedData) +{ + MapRange(CtxState, MapType, MapFlags, 0, m_Desc.uiSizeInBytes, pMappedData); +} + +void BufferGLImpl::MapRange(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFlags, Uint32 Offset, Uint32 Length, PVoid& pMappedData) { BufferMemoryBarrier( GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT, // Access by the client to persistent mapped regions of buffer @@ -303,7 +313,7 @@ void BufferGLImpl ::Map(GLContextState& CtxState, MAP_TYPE MapType, Uint32 MapFl default: UNEXPECTED("Unknown map type"); } - pMappedData = glMapBufferRange(m_BindTarget, 0, m_Desc.uiSizeInBytes, Access); + pMappedData = glMapBufferRange(m_BindTarget, Offset, Length, Access); CHECK_GL_ERROR("glMapBufferRange() failed"); VERIFY(pMappedData, "Map failed"); } diff --git a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp index 916c30a8..807a0b0a 100644 --- a/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/DeviceContextGLImpl.cpp @@ -1123,8 +1123,102 @@ void DeviceContextGLImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) TDeviceContextBase::CopyTexture(CopyAttribs); auto* pSrcTexGL = ValidatedCast(CopyAttribs.pSrcTexture); auto* pDstTexGL = ValidatedCast(CopyAttribs.pDstTexture); - pDstTexGL->CopyData(this, pSrcTexGL, CopyAttribs.SrcMipLevel, CopyAttribs.SrcSlice, CopyAttribs.pSrcBox, - CopyAttribs.DstMipLevel, CopyAttribs.DstSlice, CopyAttribs.DstX, CopyAttribs.DstY, CopyAttribs.DstZ); + + const auto& SrcTexDesc = pSrcTexGL->GetDesc(); + const auto& DstTexDesc = pDstTexGL->GetDesc(); + + auto SrcMipLevelAttribs = GetMipLevelProperties(SrcTexDesc, CopyAttribs.SrcMipLevel); + + Box FullSrcBox; + FullSrcBox.MaxX = SrcMipLevelAttribs.LogicalWidth; + FullSrcBox.MaxY = SrcMipLevelAttribs.LogicalHeight; + FullSrcBox.MaxZ = SrcMipLevelAttribs.Depth; + auto* pSrcBox = CopyAttribs.pSrcBox != nullptr ? CopyAttribs.pSrcBox : &FullSrcBox; + + if (SrcTexDesc.Usage == USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) + { + TextureSubResData SubresData; + SubresData.pData = nullptr; + SubresData.pSrcBuffer = pSrcTexGL->GetPBO(); + SubresData.SrcOffset = TextureBaseGL::GetPBODataOffset(SrcTexDesc, CopyAttribs.SrcSlice, CopyAttribs.SrcMipLevel); + SubresData.Stride = SrcMipLevelAttribs.RowSize; + SubresData.DepthStride = SrcMipLevelAttribs.DepthSliceSize; + + const auto& SrcFmtAttribs = GetTextureFormatAttribs(SrcTexDesc.Format); + SubresData.SrcOffset += + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (pSrcBox->MinZ * SrcMipLevelAttribs.StorageHeight + pSrcBox->MinY) / SrcFmtAttribs.BlockHeight * SrcMipLevelAttribs.RowSize + + // For non-compressed formats, BlockWidth is 1. + (pSrcBox->MinX / SrcFmtAttribs.BlockWidth) * SrcFmtAttribs.GetElementSize(); + + Box DstBox; + DstBox.MinX = CopyAttribs.DstX; + DstBox.MinY = CopyAttribs.DstY; + DstBox.MinZ = CopyAttribs.DstZ; + DstBox.MaxX = DstBox.MinX + pSrcBox->MaxX - pSrcBox->MinX; + DstBox.MaxY = DstBox.MinY + pSrcBox->MaxY - pSrcBox->MinY; + DstBox.MaxZ = DstBox.MinZ + pSrcBox->MaxZ - pSrcBox->MinZ; + pDstTexGL->UpdateData(m_ContextState, CopyAttribs.DstMipLevel, CopyAttribs.DstSlice, DstBox, SubresData); + } + else if (SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage == USAGE_STAGING) + { + auto CurrentNativeGLContext = m_ContextState.GetCurrentGLContext(); + auto& FBOCache = m_pDevice->GetFBOCache(CurrentNativeGLContext); + + { + TextureViewDesc SrcTexViewDesc; + SrcTexViewDesc.ViewType = TEXTURE_VIEW_RENDER_TARGET; + SrcTexViewDesc.MostDetailedMip = CopyAttribs.SrcMipLevel; + SrcTexViewDesc.FirstArraySlice = CopyAttribs.SrcSlice; + TextureViewGLImpl SrcTexView // + { + nullptr, // pRefCounters + m_pDevice, + SrcTexViewDesc, + pSrcTexGL, + false, // bCreateGLViewTex + false // bIsDefaultView + }; + + TextureViewGLImpl* pSrcViews[] = {&SrcTexView}; + const auto& SrcFBO = FBOCache.GetFBO(1, pSrcViews, nullptr, m_ContextState); + glBindFramebuffer(GL_READ_FRAMEBUFFER, SrcFBO); + DEV_CHECK_GL_ERROR("Failed to bind FBO as read framebuffer"); + } + + auto* pDstBuffer = ValidatedCast(pDstTexGL->GetPBO()); + VERIFY(pDstBuffer != nullptr, "Internal staging buffer must not be null"); + auto DstOffset = TextureBaseGL::GetPBODataOffset(DstTexDesc, CopyAttribs.DstSlice, CopyAttribs.DstMipLevel); + + auto DstMipLevelAttribs = GetMipLevelProperties(DstTexDesc, CopyAttribs.DstMipLevel); + + const auto& DstFmtAttribs = GetTextureFormatAttribs(DstTexDesc.Format); + DstOffset += + // For compressed-block formats, RowSize is the size of one compressed row. + // For non-compressed formats, BlockHeight is 1. + (CopyAttribs.DstZ * DstMipLevelAttribs.StorageHeight + CopyAttribs.DstY) / DstFmtAttribs.BlockHeight * DstMipLevelAttribs.RowSize + + // For non-compressed formats, BlockWidth is 1. + (CopyAttribs.DstX / DstFmtAttribs.BlockWidth) * DstFmtAttribs.GetElementSize(); + + m_ContextState.BindBuffer(GL_PIXEL_PACK_BUFFER, pDstBuffer->GetGLHandle(), true); + + const auto& TransferAttribs = GetNativePixelTransferAttribs(SrcTexDesc.Format); + glReadPixels(pSrcBox->MinX, pSrcBox->MinY, pSrcBox->MaxX - pSrcBox->MinX, pSrcBox->MaxY - pSrcBox->MinY, + TransferAttribs.PixelFormat, TransferAttribs.DataType, reinterpret_cast(static_cast(DstOffset))); + DEV_CHECK_GL_ERROR("Failed to read pixel from framebuffer to pixel pack buffer"); + + m_ContextState.BindBuffer(GL_PIXEL_PACK_BUFFER, GLObjectWrappers::GLBufferObj::Null(), true); + // Restore original FBO + m_ContextState.InvalidateFBO(); + CommitRenderTargets(); + } + else + { + VERIFY(SrcTexDesc.Usage != USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING, "Copying between staging textures is not supported"); + pDstTexGL->CopyData(this, pSrcTexGL, CopyAttribs.SrcMipLevel, CopyAttribs.SrcSlice, CopyAttribs.pSrcBox, + CopyAttribs.DstMipLevel, CopyAttribs.DstSlice, CopyAttribs.DstX, CopyAttribs.DstY, CopyAttribs.DstZ); + } } void DeviceContextGLImpl::MapTextureSubresource(ITexture* pTexture, @@ -1136,15 +1230,40 @@ void DeviceContextGLImpl::MapTextureSubresource(ITexture* pTextu MappedTextureSubresource& MappedData) { TDeviceContextBase::MapTextureSubresource(pTexture, MipLevel, ArraySlice, MapType, MapFlags, pMapRegion, MappedData); - LOG_ERROR_MESSAGE("Texture mapping is not supported in OpenGL"); - MappedData = MappedTextureSubresource{}; + auto* pTexGL = ValidatedCast(pTexture); + const auto& TexDesc = pTexGL->GetDesc(); + if (TexDesc.Usage == USAGE_STAGING) + { + auto PBOOffset = TextureBaseGL::GetPBODataOffset(TexDesc, ArraySlice, MipLevel); + auto MipLevelAttribs = GetMipLevelProperties(TexDesc, MipLevel); + auto pPBO = ValidatedCast(pTexGL->GetPBO()); + pPBO->MapRange(m_ContextState, MapType, MapFlags, PBOOffset, MipLevelAttribs.MipSize, MappedData.pData); + + MappedData.Stride = MipLevelAttribs.RowSize; + MappedData.DepthStride = MipLevelAttribs.MipSize; + } + else + { + LOG_ERROR_MESSAGE("Only staging textures can be mapped in OpenGL"); + MappedData = MappedTextureSubresource{}; + } } void DeviceContextGLImpl::UnmapTextureSubresource(ITexture* pTexture, Uint32 MipLevel, Uint32 ArraySlice) { TDeviceContextBase::UnmapTextureSubresource(pTexture, MipLevel, ArraySlice); - LOG_ERROR_MESSAGE("Texture mapping is not supported in OpenGL"); + auto* pTexGL = ValidatedCast(pTexture); + const auto& TexDesc = pTexGL->GetDesc(); + if (TexDesc.Usage == USAGE_STAGING) + { + auto pPBO = ValidatedCast(pTexGL->GetPBO()); + pPBO->Unmap(m_ContextState); + } + else + { + LOG_ERROR_MESSAGE("Only staging textures can be mapped in OpenGL"); + } } void DeviceContextGLImpl::GenerateMips(ITextureView* pTexView) diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp index 1dc43a13..14ada4dd 100644 --- a/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/Texture1DArray_OGL.cpp @@ -52,6 +52,12 @@ Texture1DArray_OGL::Texture1DArray_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + GLState.BindTexture(-1, m_BindTarget, m_GlTexture); // levels format width height diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp index 95fb1123..5bff6605 100644 --- a/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/Texture1D_OGL.cpp @@ -52,6 +52,12 @@ Texture1D_OGL::Texture1D_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + GLState.BindTexture(-1, m_BindTarget, m_GlTexture); // levels format width diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp index c333becc..6466749b 100644 --- a/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/Texture2DArray_OGL.cpp @@ -53,6 +53,12 @@ Texture2DArray_OGL::Texture2DArray_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + GLState.BindTexture(-1, m_BindTarget, m_GlTexture); if (m_Desc.SampleCount > 1) diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp index 598a6280..5d82e317 100644 --- a/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/Texture2D_OGL.cpp @@ -53,6 +53,12 @@ Texture2D_OGL::Texture2D_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + GLState.BindTexture(-1, m_BindTarget, m_GlTexture); if (m_Desc.SampleCount > 1) diff --git a/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp index 319ab0f0..5164fcdc 100644 --- a/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/Texture3D_OGL.cpp @@ -53,6 +53,12 @@ Texture3D_OGL::Texture3D_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + GLState.BindTexture(-1, m_BindTarget, m_GlTexture); // levels format width height depth diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp index 0aefa95f..740e73b7 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureBaseGL.cpp @@ -35,6 +35,38 @@ namespace Diligent { + +Uint32 TextureBaseGL::GetPBODataOffset(const TextureDesc& TexDesc, Uint32 ArraySlice, Uint32 MipLevel) +{ + VERIFY_EXPR(ArraySlice < TexDesc.ArraySize && MipLevel < TexDesc.MipLevels || ArraySlice == TexDesc.ArraySize && MipLevel == 0); + + Uint32 Offset = 0; + if (ArraySlice > 0) + { + Uint32 ArraySliceSize = 0; + for (Uint32 mip = 0; mip < TexDesc.MipLevels; ++mip) + { + auto MipInfo = GetMipLevelProperties(TexDesc, mip); + ArraySliceSize += (MipInfo.MipSize + 3) & (~3); + } + + Offset = ArraySliceSize; + if (TexDesc.Type == RESOURCE_DIM_TEX_1D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_2D_ARRAY || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE || + TexDesc.Type == RESOURCE_DIM_TEX_CUBE_ARRAY) + Offset *= TexDesc.ArraySize; + } + + for (Uint32 mip = 0; mip < MipLevel; ++mip) + { + auto MipInfo = GetMipLevelProperties(TexDesc, mip); + Offset += (MipInfo.MipSize + 3) & (~3); + } + + return Offset; +} + TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, FixedBlockMemoryAllocator& TexViewObjAllocator, RenderDeviceGLImpl* pDeviceGL, @@ -51,7 +83,7 @@ TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, TexDesc, bIsDeviceInternal }, - m_GlTexture {true }, // Create Texture immediately + m_GlTexture {TexDesc.Usage != USAGE_STAGING}, m_BindTarget {BindTarget }, m_GLTexFormat {TexFormatToGLInternalTexFormat(m_Desc.Format, m_Desc.BindFlags)} //m_uiMapTarget(0) @@ -60,6 +92,22 @@ TextureBaseGL::TextureBaseGL(IReferenceCounters* pRefCounters, VERIFY(m_GLTexFormat != 0, "Unsupported texture format"); if (TexDesc.Usage == USAGE_STATIC && pInitData == nullptr) LOG_ERROR_AND_THROW("Static Texture must be initialized with data at creation time"); + + if (TexDesc.Usage == USAGE_STAGING) + { + BufferDesc StagingBufferDesc; + std::string StagingBuffName = "Internal staging buffer of texture '"; + StagingBuffName += m_Desc.Name; + StagingBuffName += '\''; + StagingBufferDesc.Name = StagingBuffName.c_str(); + + StagingBufferDesc.uiSizeInBytes = GetPBODataOffset(m_Desc, m_Desc.ArraySize, 0); + StagingBufferDesc.Usage = USAGE_STAGING; + StagingBufferDesc.CPUAccessFlags = TexDesc.CPUAccessFlags; + + pDeviceGL->CreateBuffer(StagingBufferDesc, nullptr, &m_pPBO); + VERIFY_EXPR(m_pPBO); + } } static GLenum GetTextureInternalFormat(GLContextState& GLState, GLenum BindTarget, const GLObjectWrappers::GLTextureObj& GLTex, TEXTURE_FORMAT TexFmtFromDesc) @@ -389,7 +437,7 @@ void TextureBaseGL::UpdateData(GLContextState& CtxState, Uint32 MipLevel, Uint32 TextureMemoryBarrier(GL_TEXTURE_UPDATE_BARRIER_BIT, CtxState); } -//void TextureBaseGL :: UpdateData(Uint32 Offset, Uint32 Size, const PVoid pData) +//void TextureBaseGL::UpdateData(Uint32 Offset, Uint32 Size, const PVoid pData) //{ // CTexture::UpdateData(Offset, Size, pData); // @@ -399,16 +447,16 @@ void TextureBaseGL::UpdateData(GLContextState& CtxState, Uint32 MipLevel, Uint32 //} // -void TextureBaseGL ::CopyData(DeviceContextGLImpl* pDeviceCtxGL, - TextureBaseGL* pSrcTextureGL, - Uint32 SrcMipLevel, - Uint32 SrcSlice, - const Box* pSrcBox, - Uint32 DstMipLevel, - Uint32 DstSlice, - Uint32 DstX, - Uint32 DstY, - Uint32 DstZ) +void TextureBaseGL::CopyData(DeviceContextGLImpl* pDeviceCtxGL, + TextureBaseGL* pSrcTextureGL, + Uint32 SrcMipLevel, + Uint32 SrcSlice, + const Box* pSrcBox, + Uint32 DstMipLevel, + Uint32 DstSlice, + Uint32 DstX, + Uint32 DstY, + Uint32 DstZ) { const auto& SrcTexDesc = pSrcTextureGL->GetDesc(); diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp index 99c08e2c..9e32c6d8 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureCubeArray_OGL.cpp @@ -53,6 +53,12 @@ TextureCubeArray_OGL::TextureCubeArray_OGL(IReferenceCounters* pRefCounte } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + VERIFY(m_Desc.SampleCount == 1, "Multisampled texture cube arrays are not supported"); GLState.BindTexture(-1, m_BindTarget, m_GlTexture); diff --git a/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp b/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp index 0dfa6edc..82bf933d 100644 --- a/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp +++ b/Graphics/GraphicsEngineOpenGL/src/TextureCube_OGL.cpp @@ -53,6 +53,12 @@ TextureCube_OGL::TextureCube_OGL(IReferenceCounters* pRefCounters, } // clang-format on { + if (TexDesc.Usage == USAGE_STAGING) + { + // We will use PBO initialized by TextureBaseGL + return; + } + VERIFY(m_Desc.SampleCount == 1, "Multisampled cubemap textures are not supported"); GLState.BindTexture(-1, m_BindTarget, m_GlTexture); 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