diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-05-04 12:00:53 -0400 |
|---|---|---|
| committer | Tim Foley <tfoleyNV@users.noreply.github.com> | 2018-05-04 09:00:53 -0700 |
| commit | ee47232fc17f31ef2bd95ca480372216a79def56 (patch) | |
| tree | 75d1fdd76e2ed4e081699aaae8b6df819f181260 | |
| parent | 494330d4941ccaf50e07ef309fd783c2f44a492e (diff) | |
Use Surface for screen capture in Renderer interface (#551)
* Remove serialization of screen captures from a renderer implementation, capture now writes to a Surface. Then client code can decide to serialize (or use as needed).
* Improved comment for captureScreenSurface.
| -rw-r--r-- | tools/render-test/main.cpp | 15 | ||||
| -rw-r--r-- | tools/render-test/render-d3d11.cpp | 42 | ||||
| -rw-r--r-- | tools/render-test/render-d3d12.cpp | 18 | ||||
| -rw-r--r-- | tools/render-test/render-gl.cpp | 14 | ||||
| -rw-r--r-- | tools/render-test/render-vk.cpp | 4 | ||||
| -rw-r--r-- | tools/render-test/render.h | 6 | ||||
| -rw-r--r-- | tools/render-test/surface.cpp | 31 | ||||
| -rw-r--r-- | tools/render-test/surface.h | 3 |
8 files changed, 83 insertions, 50 deletions
diff --git a/tools/render-test/main.cpp b/tools/render-test/main.cpp index df9220b58..adcad42a7 100644 --- a/tools/render-test/main.cpp +++ b/tools/render-test/main.cpp @@ -8,6 +8,8 @@ #include "render-vk.h" #include "slang-support.h" +#include "surface.h" +#include "png-serialize-util.h" #include "shader-renderer-util.h" @@ -68,6 +70,8 @@ class RenderTestApp Result writeBindingOutput(const char* fileName); + Result writeScreen(const char* filename); + protected: /// Called in initialize Result initializeShaders(ShaderCompiler* shaderCompiler); @@ -312,6 +316,14 @@ Result RenderTestApp::writeBindingOutput(const char* fileName) return SLANG_OK; } + +Result RenderTestApp::writeScreen(const char* filename) +{ + Surface surface; + SLANG_RETURN_ON_FAIL(m_renderer->captureScreenSurface(surface)); + return PngSerializeUtil::write(filename, surface); +} + // // We use a bare-minimum window procedure to get things up and running. // @@ -504,7 +516,8 @@ SlangResult innerMain(int argc, char** argv) } else { - Result res = renderer->captureScreenShot(gOptions.outputPath); + Result res = app.writeScreen(gOptions.outputPath); + if (SLANG_FAILED(res)) { fprintf(stderr, "ERROR: failed to write screen capture to file\n"); diff --git a/tools/render-test/render-d3d11.cpp b/tools/render-test/render-d3d11.cpp index 96835f313..9523d37cd 100644 --- a/tools/render-test/render-d3d11.cpp +++ b/tools/render-test/render-d3d11.cpp @@ -8,14 +8,14 @@ #include "render.h" #include "d3d-util.h" +#include "surface.h" + // In order to use the Slang API, we need to include its header #include <slang.h> #include "../../source/core/slang-com-ptr.h" -#include "png-serialize-util.h" - // We will be rendering with Direct3D 11, so we need to include // the Windows and D3D11 headers @@ -52,7 +52,7 @@ public: virtual void presentFrame() override; virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; virtual InputLayout* createInputLayout( const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState* createBindingState(const BindingState::Desc& desc) override; virtual ShaderCompiler* getShaderCompiler() override; @@ -141,7 +141,7 @@ public: }; /// Capture a texture to a file - static HRESULT captureTextureToFile(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, char const* outputPath); + static HRESULT captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut); void _applyBindingState(bool isCompute); @@ -165,8 +165,7 @@ Renderer* createD3D11Renderer() return new D3D11Renderer(); } -/* static */HRESULT D3D11Renderer::captureTextureToFile(ID3D11Device* device, ID3D11DeviceContext* context, - ID3D11Texture2D* texture, char const* outputPath) +/* static */HRESULT D3D11Renderer::captureTextureToSurface(ID3D11Device* device, ID3D11DeviceContext* context, ID3D11Texture2D* texture, Surface& surfaceOut) { if (!context) return E_INVALIDARG; if (!texture) return E_INVALIDARG; @@ -207,23 +206,16 @@ Renderer* createD3D11Renderer() } // Now just read back texels from the staging textures - - D3D11_MAPPED_SUBRESOURCE mappedResource; - hr = context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource); - if (FAILED(hr)) { - fprintf(stderr, "ERROR: failed to map texture for read\n"); - return hr; - } - - Surface surface; - surface.setUnowned(textureDesc.Width, textureDesc.Height, Format::RGBA_Unorm_UInt8, mappedResource.RowPitch, mappedResource.pData); + D3D11_MAPPED_SUBRESOURCE mappedResource; + SLANG_RETURN_ON_FAIL(context->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mappedResource)); - Result res = PngSerializeUtil::write(outputPath, surface); + Result res = surfaceOut.set(textureDesc.Width, textureDesc.Height, Format::RGBA_Unorm_UInt8, mappedResource.RowPitch, mappedResource.pData, SurfaceAllocator::getMallocAllocator()); - // Make sure to unmap - context->Unmap(stagingTexture, 0); - return res; + // Make sure to unmap + context->Unmap(stagingTexture, 0); + return res; + } } // !!!!!!!!!!!!!!!!!!!!!!!!!!!! Renderer interface !!!!!!!!!!!!!!!!!!!!!!!!!! @@ -385,15 +377,9 @@ void D3D11Renderer::presentFrame() m_swapChain->Present(0, 0); } -SlangResult D3D11Renderer::captureScreenShot(const char* outputPath) +SlangResult D3D11Renderer::captureScreenSurface(Surface& surfaceOut) { - HRESULT hr = captureTextureToFile(m_device, m_immediateContext, m_renderTargetTextures[0], outputPath); - if (FAILED(hr)) - { - fprintf(stderr, "error: could not capture screen-shot to '%s'\n", outputPath); - SLANG_RETURN_ON_FAIL(hr); - } - return SLANG_OK; + return captureTextureToSurface(m_device, m_immediateContext, m_renderTargetTextures[0], surfaceOut); } ShaderCompiler* D3D11Renderer::getShaderCompiler() diff --git a/tools/render-test/render-d3d12.cpp b/tools/render-test/render-d3d12.cpp index d1b547f2d..a582e3feb 100644 --- a/tools/render-test/render-d3d12.cpp +++ b/tools/render-test/render-d3d12.cpp @@ -6,6 +6,8 @@ #include "options.h" #include "render.h" +#include "surface.h" + // In order to use the Slang API, we need to include its header #include <slang.h> @@ -25,8 +27,6 @@ #include "../../source/core/slang-com-ptr.h" -#include "png-serialize-util.h" - #include "resource-d3d12.h" #include "descriptor-heap-d3d12.h" #include "circular-resource-heap-d3d12.h" @@ -59,7 +59,7 @@ public: virtual void presentFrame() override; virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenShot(const char* outputPath) override; + virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; virtual ShaderCompiler* getShaderCompiler() override; @@ -326,7 +326,7 @@ protected: void submitGpuWorkAndWait(); void _resetCommandList(); - Result captureTextureToFile(D3D12Resource& resource, const char* outputPath); + Result captureTextureToSurface(D3D12Resource& resource, Surface& surfaceOut); FrameInfo& getFrame() { return m_frameInfos[m_frameIndex]; } const FrameInfo& getFrame() const { return m_frameInfos[m_frameIndex]; } @@ -721,7 +721,7 @@ void D3D12Renderer::submitGpuWorkAndWait() waitForGpu(); } -Result D3D12Renderer::captureTextureToFile(D3D12Resource& resource, const char* outputPath) +Result D3D12Renderer::captureTextureToSurface(D3D12Resource& resource, Surface& surfaceOut) { const D3D12_RESOURCE_STATES initialState = resource.getState(); @@ -794,9 +794,7 @@ Result D3D12Renderer::captureTextureToFile(D3D12Resource& resource, const char* SLANG_RETURN_ON_FAIL(dxResource->Map(0, &readRange, reinterpret_cast<void**>(&data))); - Surface surface; - surface.setUnowned(int(desc.Width), int(desc.Height), Format::RGBA_Unorm_UInt8, int(rowPitch), data); - Result res = PngSerializeUtil::write(outputPath, surface); + Result res = surfaceOut.set(int(desc.Width), int(desc.Height), Format::RGBA_Unorm_UInt8, int(rowPitch), data, SurfaceAllocator::getMallocAllocator()); dxResource->Unmap(0, nullptr); return res; @@ -1681,9 +1679,9 @@ void D3D12Renderer::presentFrame() beginRender(); } -SlangResult D3D12Renderer::captureScreenShot(const char* outputPath) +SlangResult D3D12Renderer::captureScreenSurface(Surface& surfaceOut) { - return captureTextureToFile(*m_renderTargets[m_renderTargetIndex], outputPath); + return captureTextureToSurface(*m_renderTargets[m_renderTargetIndex], surfaceOut); } ShaderCompiler* D3D12Renderer::getShaderCompiler() diff --git a/tools/render-test/render-gl.cpp b/tools/render-test/render-gl.cpp index cef482798..2c4ac9ea0 100644 --- a/tools/render-test/render-gl.cpp +++ b/tools/render-test/render-gl.cpp @@ -12,7 +12,6 @@ #include "external/stb/stb_image_write.h" #include "surface.h" -#include "png-serialize-util.h" // TODO(tfoley): eventually we should be able to run these // tests on non-Windows targets to confirm that cross-compilation @@ -87,7 +86,7 @@ public: virtual void presentFrame() override; virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& descIn, const void* initData) override; - virtual SlangResult captureScreenShot(char const* outputPath) override; + virtual SlangResult captureScreenSurface(Surface& surfaceOut) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; virtual ShaderCompiler* getShaderCompiler() override; @@ -586,13 +585,12 @@ void GLRenderer::presentFrame() ::SwapBuffers(m_hdc); } -SlangResult GLRenderer::captureScreenShot(const char* outputPath) +SlangResult GLRenderer::captureScreenSurface(Surface& surfaceOut) { - Surface surface; - surface.allocate(m_desc.width, m_desc.height, Format::RGBA_Unorm_UInt8, 1, SurfaceAllocator::getMallocAllocator()); - glReadPixels(0, 0, m_desc.width, m_desc.height, GL_RGBA, GL_UNSIGNED_BYTE, surface.m_data); - surface.flipInplaceVertically(); - return PngSerializeUtil::write(outputPath, surface); + SLANG_RETURN_ON_FAIL(surfaceOut.allocate(m_desc.width, m_desc.height, Format::RGBA_Unorm_UInt8, 1, SurfaceAllocator::getMallocAllocator())); + glReadPixels(0, 0, m_desc.width, m_desc.height, GL_RGBA, GL_UNSIGNED_BYTE, surfaceOut.m_data); + surfaceOut.flipInplaceVertically(); + return SLANG_OK; } ShaderCompiler* GLRenderer::getShaderCompiler() diff --git a/tools/render-test/render-vk.cpp b/tools/render-test/render-vk.cpp index 8ffb05c99..cc011a297 100644 --- a/tools/render-test/render-vk.cpp +++ b/tools/render-test/render-vk.cpp @@ -39,7 +39,7 @@ public: virtual void presentFrame() override; virtual TextureResource* createTextureResource(Resource::Type type, Resource::Usage initialUsage, const TextureResource::Desc& desc, const TextureResource::Data* initData) override; virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& bufferDesc, const void* initData) override; - virtual SlangResult captureScreenShot(const char* outputPath) override; + virtual SlangResult captureScreenSurface(Surface& surface) override; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) override; virtual BindingState* createBindingState(const BindingState::Desc& bindingStateDesc) override; virtual ShaderCompiler* getShaderCompiler() override; @@ -1010,7 +1010,7 @@ void VKRenderer::presentFrame() _beginRender(); } -SlangResult VKRenderer::captureScreenShot(char const* outputPath) +SlangResult VKRenderer::captureScreenSurface(Surface& surfaceOut) { return SLANG_FAIL; } diff --git a/tools/render-test/render.h b/tools/render-test/render.h index ba76f795d..f66454712 100644 --- a/tools/render-test/render.h +++ b/tools/render-test/render.h @@ -15,6 +15,9 @@ namespace renderer_test { typedef intptr_t Int; typedef uintptr_t UInt; +// pre declare types +class Surface; + // Declare opaque type class InputLayout: public Slang::RefObject { @@ -552,7 +555,8 @@ public: /// Create a buffer resource virtual BufferResource* createBufferResource(Resource::Usage initialUsage, const BufferResource::Desc& desc, const void* initData = nullptr) { return nullptr; } - virtual SlangResult captureScreenShot(const char* outputPath) = 0; + /// Captures the back buffer and stores the result in surfaceOut. If the surface contains data - it will either be overwritten (if same size and format), or freed and a re-allocated. + virtual SlangResult captureScreenSurface(Surface& surfaceOut) = 0; virtual InputLayout* createInputLayout(const InputElementDesc* inputElements, UInt inputElementCount) = 0; virtual BindingState* createBindingState(const BindingState::Desc& desc) { return nullptr; } diff --git a/tools/render-test/surface.cpp b/tools/render-test/surface.cpp index 3f96052ce..4d761389a 100644 --- a/tools/render-test/surface.cpp +++ b/tools/render-test/surface.cpp @@ -188,4 +188,35 @@ void Surface::flipInplaceVertically() } } +SlangResult Surface::set(int width, int height, Format format, int srcRowStride, const void* data, SurfaceAllocator* allocator) +{ + if (hasContents() && m_width == width && m_height == height && m_format == format) + { + // I can just overwrite the contents that is there + } + else + { + SLANG_RETURN_ON_FAIL(allocate(width, height, format, 0, allocator)); + } + + // Okay just need to set the contents + + { + const size_t rowSize = calcRowSize(format, width); + + const uint8_t* srcRow = (const uint8_t*)data; + uint8_t* dstRow = (uint8_t*)m_data; + + for (int i = 0; i < m_numRows; i++) + { + ::memcpy(dstRow, srcRow, rowSize); + + srcRow += srcRowStride; + dstRow += m_rowStrideInBytes; + } + } + + return SLANG_OK; +} + } // renderer_test diff --git a/tools/render-test/surface.h b/tools/render-test/surface.h index f5f67efc0..c7460238f 100644 --- a/tools/render-test/surface.h +++ b/tools/render-test/surface.h @@ -37,6 +37,9 @@ class Surface /// Set unowned void setUnowned(int width, int height, Format format, int strideInBytes, void* data); + /// Set the contents - the memory will be owned by this surface (ie will be freed by the allocator when goes out of scope or is deallocated) + Slang::Result set(int width, int height, Format format, int strideInBytes, const void* data, SurfaceAllocator* allocator); + template <typename T> T* calcNextRow(T* ptr) const { return (T*)calcNextRow((void*)ptr); } template <typename T> |
