From 6aa6efda12b80fbc00f9d53394e4af7fe9593264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Branimir=20Karad=C5=BEi=C4=87?= Date: Tue, 20 Oct 2015 16:32:08 -0700 Subject: [PATCH] Added initial texture read back support. --- examples/08-update/update.cpp | 2 +- examples/09-hdr/hdr.cpp | 28 +++++++++++++++++- examples/common/nanovg/nanovg_bgfx.cpp | 2 +- include/bgfx/bgfx.h | 12 ++++++++ include/bgfx/bgfxdefines.h | 4 ++- src/bgfx.cpp | 39 +++++++++++++++++++++++++- src/bgfx_p.h | 27 ++++++++++++++++++ src/glimports.h | 7 +++++ src/renderer_d3d11.cpp | 39 ++++++++++++++++++++++++-- src/renderer_d3d12.cpp | 6 +++- src/renderer_d3d9.cpp | 34 +++++++++++++++++++++- src/renderer_gl.cpp | 34 +++++++++++++++++++++- src/renderer_mtl.mm | 4 +++ src/renderer_null.cpp | 4 +++ 14 files changed, 232 insertions(+), 10 deletions(-) diff --git a/examples/08-update/update.cpp b/examples/08-update/update.cpp index 3bfc6d1ce..bb85146a8 100644 --- a/examples/08-update/update.cpp +++ b/examples/08-update/update.cpp @@ -169,7 +169,7 @@ int _main_(int /*_argc*/, char** /*_argv*/) const bgfx::Caps* caps = bgfx::getCaps(); const bool texture3DSupported = !!(caps->supported & BGFX_CAPS_TEXTURE_3D); - const bool blitSupported = !!(caps->supported & BGFX_CAPS_BLIT); + const bool blitSupported = !!(caps->supported & BGFX_CAPS_TEXTURE_BLIT); uint32_t numTextures3d = 0; bgfx::TextureHandle textures3d[3] = {}; diff --git a/examples/09-hdr/hdr.cpp b/examples/09-hdr/hdr.cpp index 9ad7eb5ae..0d70774fe 100644 --- a/examples/09-hdr/hdr.cpp +++ b/examples/09-hdr/hdr.cpp @@ -215,6 +215,16 @@ class HDR : public entry::AppI m_bright = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Half, bgfx::TextureFormat::BGRA8); m_blur = bgfx::createFrameBuffer(bgfx::BackbufferRatio::Eighth, bgfx::TextureFormat::BGRA8); + m_lumBgra8 = 0; + if ( (BGFX_CAPS_TEXTURE_BLIT|BGFX_CAPS_TEXTURE_READ_BACK) == (bgfx::getCaps()->supported & BGFX_CAPS_TEXTURE_BLIT|BGFX_CAPS_TEXTURE_READ_BACK) ) + { + m_rb = bgfx::createTexture2D(1, 1, 1, bgfx::TextureFormat::BGRA8, BGFX_TEXTURE_READ_BACK); + } + else + { + m_rb.idx = bgfx::invalidHandle; + } + // Imgui. imguiCreate(); @@ -306,7 +316,7 @@ class HDR : public entry::AppI , m_height ); - imguiBeginScrollArea("Settings", m_width - m_width / 5 - 10, 10, m_width / 5, m_height / 3, &m_scrollArea); + imguiBeginScrollArea("Settings", m_width - m_width / 5 - 10, 10, m_width / 5, m_height / 2, &m_scrollArea); imguiSeparatorLine(); imguiSlider("Speed", m_speed, 0.0f, 1.0f, 0.01f); @@ -316,6 +326,14 @@ class HDR : public entry::AppI imguiSlider("White point", m_white, 0.1f, 2.0f, 0.01f); imguiSlider("Threshold", m_threshold, 0.1f, 2.0f, 0.01f); + if (bgfx::isValid(m_rb) ) + { + union { uint32_t color; uint8_t bgra[4]; } cast = { m_lumBgra8 }; + float exponent = cast.bgra[3]/255.0f * 255.0f - 128.0f; + float lumAvg = cast.bgra[2]/255.0f * exp2(exponent); + imguiSlider("Lum Avg", lumAvg, 0.0f, 1.0f, 0.01f, false); + } + imguiEndScrollArea(); imguiEndFrame(); @@ -473,6 +491,12 @@ class HDR : public entry::AppI screenSpaceQuad( (float)m_width, (float)m_height, s_originBottomLeft); bgfx::submit(9, m_tonemapProgram); + if (bgfx::isValid(m_rb) ) + { + bgfx::blit(9, m_rb, 0, 0, m_lum[4]); + bgfx::readTexture(m_rb, &m_lumBgra8); + } + // Advance to next frame. Rendering thread will be kicked to // process submitted rendering primitives. bgfx::frame(); @@ -505,6 +529,7 @@ class HDR : public entry::AppI Mesh* m_mesh; bgfx::TextureHandle m_fbtextures[2]; + bgfx::TextureHandle m_rb; bgfx::FrameBufferHandle m_fbh; bgfx::FrameBufferHandle m_lum[5]; bgfx::FrameBufferHandle m_bright; @@ -514,6 +539,7 @@ class HDR : public entry::AppI uint32_t m_height; uint32_t m_debug; uint32_t m_reset; + uint32_t m_lumBgra8; uint32_t m_oldWidth; uint32_t m_oldHeight; diff --git a/examples/common/nanovg/nanovg_bgfx.cpp b/examples/common/nanovg/nanovg_bgfx.cpp index 263c1b31b..5891dc546 100644 --- a/examples/common/nanovg/nanovg_bgfx.cpp +++ b/examples/common/nanovg/nanovg_bgfx.cpp @@ -251,7 +251,7 @@ namespace vs_nanovg_fill = bgfx::makeRef(vs_nanovg_fill_mtl, sizeof(vs_nanovg_fill_mtl) ); fs_nanovg_fill = bgfx::makeRef(fs_nanovg_fill_mtl, sizeof(fs_nanovg_fill_mtl) ); break; - + default: vs_nanovg_fill = bgfx::makeRef(vs_nanovg_fill_glsl, sizeof(vs_nanovg_fill_glsl) ); fs_nanovg_fill = bgfx::makeRef(fs_nanovg_fill_glsl, sizeof(fs_nanovg_fill_glsl) ); diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 0f9a98116..6eb57abb4 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -1394,6 +1394,12 @@ namespace bgfx /// void updateTextureCube(TextureHandle _handle, uint8_t _side, uint8_t _mip, uint16_t _x, uint16_t _y, uint16_t _width, uint16_t _height, const Memory* _mem, uint16_t _pitch = UINT16_MAX); + /// + void readTexture(TextureHandle _handle, void* _data); + + /// + void readTexture(FrameBufferHandle _handle, uint8_t _attachment, void* _data); + /// Destroy texture. /// /// @attention C99 equivalent is `bgfx_destroy_texture`. @@ -2052,12 +2058,18 @@ namespace bgfx /// void blit(uint8_t _id, TextureHandle _dst, uint16_t _dstX, uint16_t _dstY, TextureHandle _src, uint16_t _srcX = 0, uint16_t _srcY = 0, uint16_t _width = UINT16_MAX, uint16_t _height = UINT16_MAX); + /// + void blit(uint8_t _id, TextureHandle _dst, uint16_t _dstX, uint16_t _dstY, FrameBufferHandle _src, uint8_t _attachment = 0, uint16_t _srcX = 0, uint16_t _srcY = 0, uint16_t _width = UINT16_MAX, uint16_t _height = UINT16_MAX); + /// Blit texture region between two textures. /// /// @attention C99 equivalent is `bgfx_blit`. /// void blit(uint8_t _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, TextureHandle _src, uint8_t _srcMip = 0, uint16_t _srcX = 0, uint16_t _srcY = 0, uint16_t _srcZ = 0, uint16_t _width = UINT16_MAX, uint16_t _height = UINT16_MAX, uint16_t _depth = UINT16_MAX); + /// + void blit(uint8_t _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, FrameBufferHandle _src, uint8_t _attachment = 0, uint8_t _srcMip = 0, uint16_t _srcX = 0, uint16_t _srcY = 0, uint16_t _srcZ = 0, uint16_t _width = UINT16_MAX, uint16_t _height = UINT16_MAX, uint16_t _depth = UINT16_MAX); + /// Request screen shot. /// /// @param[in] _filePath Will be passed to `bgfx::CallbackI::screenShot` callback. diff --git a/include/bgfx/bgfxdefines.h b/include/bgfx/bgfxdefines.h index 8d4b30aeb..9c756c060 100644 --- a/include/bgfx/bgfxdefines.h +++ b/include/bgfx/bgfxdefines.h @@ -311,6 +311,7 @@ #define BGFX_TEXTURE_COMPUTE_WRITE UINT32_C(0x00100000) //!< #define BGFX_TEXTURE_SRGB UINT32_C(0x00200000) //!< #define BGFX_TEXTURE_BLIT_DST UINT32_C(0x00400000) //!< +#define BGFX_TEXTURE_READ_BACK UINT32_C(0x00800000) //!< #define BGFX_TEXTURE_BORDER_COLOR_SHIFT 24 //!< #define BGFX_TEXTURE_BORDER_COLOR_MASK UINT32_C(0x0f000000) //!< #define BGFX_TEXTURE_RESERVED_SHIFT 28 //!< @@ -367,7 +368,8 @@ #define BGFX_CAPS_INDEX32 UINT64_C(0x0000000000002000) //!< 32-bit indices are supported. #define BGFX_CAPS_DRAW_INDIRECT UINT64_C(0x0000000000004000) //!< Draw indirect is supported. #define BGFX_CAPS_HIDPI UINT64_C(0x0000000000008000) //!< HiDPI rendering is supported. -#define BGFX_CAPS_BLIT UINT64_C(0x0000000000010000) //!< Blit is supported. +#define BGFX_CAPS_TEXTURE_BLIT UINT64_C(0x0000000000010000) //!< Texture blit is supported. +#define BGFX_CAPS_TEXTURE_READ_BACK UINT64_C(0x0000000000020000) //!< Read-back texture is supported. /// #define BGFX_CAPS_FORMAT_TEXTURE_NONE UINT8_C(0x00) //!< Texture format is not supported. diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 2b9caeb70..bdcc54aa5 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -977,7 +977,7 @@ namespace bgfx CAPS_FLAGS(BGFX_CAPS_INDEX32), CAPS_FLAGS(BGFX_CAPS_DRAW_INDIRECT), CAPS_FLAGS(BGFX_CAPS_HIDPI), - CAPS_FLAGS(BGFX_CAPS_BLIT), + CAPS_FLAGS(BGFX_CAPS_TEXTURE_BLIT), #undef CAPS_FLAGS }; @@ -2058,6 +2058,18 @@ again: } break; + case CommandBuffer::ReadTexture: + { + TextureHandle handle; + _cmdbuf.read(handle); + + void* data; + _cmdbuf.read(data); + + m_renderCtx->readTexture(handle, data); + } + break; + case CommandBuffer::ResizeTexture: { TextureHandle handle; @@ -2903,6 +2915,20 @@ again: } } + void readTexture(TextureHandle _handle, void* _data) + { + BGFX_CHECK_MAIN_THREAD(); + BX_CHECK(NULL != _data, "_data can't be NULL"); + s_ctx->readTexture(_handle, _data); + } + + void readTexture(FrameBufferHandle _handle, uint8_t _attachment, void* _data) + { + BGFX_CHECK_MAIN_THREAD(); + BX_CHECK(NULL != _data, "_data can't be NULL"); + s_ctx->readTexture(_handle, _attachment, _data); + } + FrameBufferHandle createFrameBuffer(uint16_t _width, uint16_t _height, TextureFormat::Enum _format, uint32_t _textureFlags) { _textureFlags |= _textureFlags&BGFX_TEXTURE_RT_MSAA_MASK ? 0 : BGFX_TEXTURE_RT; @@ -3278,12 +3304,23 @@ again: blit(_id, _dst, 0, _dstX, _dstY, 0, _src, 0, _srcX, _srcY, 0, _width, _height, 0); } + void blit(uint8_t _id, TextureHandle _dst, uint16_t _dstX, uint16_t _dstY, FrameBufferHandle _src, uint8_t _attachment, uint16_t _srcX, uint16_t _srcY, uint16_t _width, uint16_t _height) + { + blit(_id, _dst, 0, _dstX, _dstY, 0, _src, _attachment, 0, _srcX, _srcY, 0, _width, _height, 0); + } + void blit(uint8_t _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, TextureHandle _src, uint8_t _srcMip, uint16_t _srcX, uint16_t _srcY, uint16_t _srcZ, uint16_t _width, uint16_t _height, uint16_t _depth) { BGFX_CHECK_MAIN_THREAD(); s_ctx->blit(_id, _dst, _dstMip, _dstX, _dstY, _dstZ, _src, _srcMip, _srcX, _srcY, _srcZ, _width, _height, _depth); } + void blit(uint8_t _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, FrameBufferHandle _src, uint8_t _attachment, uint8_t _srcMip, uint16_t _srcX, uint16_t _srcY, uint16_t _srcZ, uint16_t _width, uint16_t _height, uint16_t _depth) + { + BGFX_CHECK_MAIN_THREAD(); + s_ctx->blit(_id, _dst, _dstMip, _dstX, _dstY, _dstZ, _src, _attachment, _srcMip, _srcX, _srcY, _srcZ, _width, _height, _depth); + } + void saveScreenShot(const char* _filePath) { BGFX_CHECK_MAIN_THREAD(); diff --git a/src/bgfx_p.h b/src/bgfx_p.h index db33dfd15..5c2834c2b 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -583,6 +583,7 @@ namespace bgfx DestroyTexture, DestroyFrameBuffer, DestroyUniform, + ReadTexture, SaveScreenShot, }; @@ -1941,6 +1942,7 @@ namespace bgfx virtual void updateTextureBegin(TextureHandle _handle, uint8_t _side, uint8_t _mip) = 0; virtual void updateTexture(TextureHandle _handle, uint8_t _side, uint8_t _mip, const Rect& _rect, uint16_t _z, uint16_t _depth, uint16_t _pitch, const Memory* _mem) = 0; virtual void updateTextureEnd() = 0; + virtual void readTexture(TextureHandle _handle, void* _data) = 0; virtual void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) = 0; virtual void destroyTexture(TextureHandle _handle) = 0; virtual void createFrameBuffer(FrameBufferHandle _handle, uint8_t _num, const TextureHandle* _textureHandles) = 0; @@ -2990,6 +2992,22 @@ namespace bgfx textureDecRef(_handle); } + BGFX_API_FUNC(void readTexture(TextureHandle _handle, void* _data) ) + { + CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ReadTexture); + cmdbuf.write(_handle); + cmdbuf.write(_data); + } + + BGFX_API_FUNC(void readTexture(FrameBufferHandle _handle, uint8_t _attachment, void* _data) ) + { + const FrameBufferRef& ref = m_frameBufferRef[_handle.idx]; + BX_CHECK(!ref.m_window, "Can't sample window frame buffer."); + TextureHandle textureHandle = ref.un.m_th[_attachment]; + BX_CHECK(isValid(textureHandle), "Frame buffer texture %d is invalid.", _attachment); + readTexture(textureHandle, _data); + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) { const TextureRef& textureRef = m_textureRef[_handle.idx]; @@ -3623,6 +3641,15 @@ namespace bgfx m_submit->blit(_id, _dst, _dstMip, _dstX, _dstY, _dstZ, _src, _srcMip, _srcX, _srcY, _srcZ, _width, _height, _depth); } + BGFX_API_FUNC(void blit(uint8_t _id, TextureHandle _dst, uint8_t _dstMip, uint16_t _dstX, uint16_t _dstY, uint16_t _dstZ, FrameBufferHandle _src, uint8_t _attachment, uint8_t _srcMip, uint16_t _srcX, uint16_t _srcY, uint16_t _srcZ, uint16_t _width, uint16_t _height, uint16_t _depth) ) + { + const FrameBufferRef& ref = m_frameBufferRef[_src.idx]; + BX_CHECK(!ref.m_window, "Can't sample window frame buffer."); + TextureHandle textureHandle = ref.un.m_th[_attachment]; + BX_CHECK(isValid(textureHandle), "Frame buffer texture %d is invalid.", _attachment); + blit(_id, _dst, _dstMip, _dstX, _dstY, _dstZ, textureHandle, _srcMip, _srcX, _srcY, _srcZ, _width, _height, _depth); + } + BGFX_API_FUNC(uint32_t frame() ); void dumpViewStats(); diff --git a/src/glimports.h b/src/glimports.h index 3467cc504..272409980 100644 --- a/src/glimports.h +++ b/src/glimports.h @@ -121,6 +121,7 @@ typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuin typedef void (GL_APIENTRYP PFNGLGETACTIVEATTRIBPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef void (GL_APIENTRYP PFNGLGETACTIVEUNIFORMPROC) (GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name); typedef GLint (GL_APIENTRYP PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETCOMPRESSEDTEXIMAGEPROC) (GLenum target, GLint level, GLvoid *img); typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); typedef GLenum (GL_APIENTRYP PFNGLGETERRORPROC) (void); typedef void (GL_APIENTRYP PFNGLGETFLOATVPROC) (GLenum pname, GLfloat *data); @@ -139,6 +140,7 @@ typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCEIVPROC) (GLuint prog typedef void (GL_APIENTRYP PFNGLGETPROGRAMRESOURCENAMEPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name); typedef GLint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONPROC) (GLuint program, GLenum programInterface, const GLchar *name); typedef GLint (GL_APIENTRYP PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC) (GLuint program, GLenum programInterface, const GLchar *name); +typedef void (GL_APIENTRYP PFNGLGETTEXIMAGEPROC) (GLenum target, GLint level, GLenum format, GLenum type, void *pixels); typedef void (GL_APIENTRYP PFNGLGETQUERYIVPROC) (GLenum target, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTIVPROC) (GLuint id, GLenum pname, GLint *params); typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTI64VPROC) (GLuint id, GLenum pname, GLint64 *params); @@ -302,6 +304,7 @@ GL_IMPORT______(true, PFNGLGENVERTEXARRAYSPROC, glGenVertexAr GL_IMPORT______(false, PFNGLGETACTIVEATTRIBPROC, glGetActiveAttrib); GL_IMPORT______(false, PFNGLGETATTRIBLOCATIONPROC, glGetAttribLocation); GL_IMPORT______(false, PFNGLGETACTIVEUNIFORMPROC, glGetActiveUniform); +GL_IMPORT______(true, PFNGLGETCOMPRESSEDTEXIMAGEPROC, glGetCompressedTexImage); GL_IMPORT______(true, PFNGLGETDEBUGMESSAGELOGPROC, glGetDebugMessageLog); GL_IMPORT______(false, PFNGLGETERRORPROC, glGetError); GL_IMPORT______(false, PFNGLGETFLOATVPROC, glGetFloatv); @@ -320,6 +323,7 @@ GL_IMPORT______(true, PFNGLGETPROGRAMRESOURCEIVPROC, glGetProgramR GL_IMPORT______(true, PFNGLGETPROGRAMRESOURCENAMEPROC, glGetProgramResourceName); GL_IMPORT______(true, PFNGLGETPROGRAMRESOURCELOCATIONPROC, glGetProgramResourceLocation); GL_IMPORT______(true, PFNGLGETPROGRAMRESOURCELOCATIONINDEXPROC, glGetProgramResourceLocationIndex); +GL_IMPORT______(true, PFNGLGETTEXIMAGEPROC, glGetTexImage); GL_IMPORT______(true, PFNGLGETQUERYIVPROC, glGetQueryiv); GL_IMPORT______(true, PFNGLGETQUERYOBJECTIVPROC, glGetQueryObjectiv); GL_IMPORT______(true, PFNGLGETQUERYOBJECTI64VPROC, glGetQueryObjecti64v); @@ -519,6 +523,9 @@ GL_IMPORT_____x(true, PFNGLMEMORYBARRIERPROC, glMemoryBarri GL_IMPORT_____x(true, PFNGLDISPATCHCOMPUTEPROC, glDispatchCompute); GL_IMPORT_____x(true, PFNGLDISPATCHCOMPUTEINDIRECTPROC, glDispatchComputeIndirect); +GL_IMPORT_____x(true, PFNGLGETCOMPRESSEDTEXIMAGEPROC, glGetCompressedTexImage); +GL_IMPORT_____x(true, PFNGLGETTEXIMAGEPROC, glGetTexImage); + GL_IMPORT_NV___(true, PFNGLDRAWBUFFERSPROC, glDrawBuffers); GL_IMPORT_NV___(true, PFNGLGENQUERIESPROC, glGenQueries); GL_IMPORT_NV___(true, PFNGLDELETEQUERIESPROC, glDeleteQueries); diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index c9ef30f90..760befa76 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -1156,7 +1156,8 @@ BX_PRAGMA_DIAGNOSTIC_POP(); | BGFX_CAPS_SWAP_CHAIN | (m_ovr.isInitialized() ? BGFX_CAPS_HMD : 0) | BGFX_CAPS_DRAW_INDIRECT - | BGFX_CAPS_BLIT + | BGFX_CAPS_TEXTURE_BLIT + | BGFX_CAPS_TEXTURE_READ_BACK ); if (m_featureLevel <= D3D_FEATURE_LEVEL_9_2) @@ -1652,6 +1653,32 @@ BX_PRAGMA_DIAGNOSTIC_POP(); { } + void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + { + const TextureD3D11& texture = m_textures[_handle.idx]; + D3D11_MAPPED_SUBRESOURCE mapped; + DX_CHECK(m_deviceCtx->Map(texture.m_ptr, 0, D3D11_MAP_READ, 0, &mapped) ); + + uint8_t* src = (uint8_t*)mapped.pData; + uint32_t srcPitch = mapped.RowPitch; + + const uint8_t bpp = getBitsPerPixel(TextureFormat::Enum(texture.m_textureFormat) ); + uint8_t* dst = (uint8_t*)_data; + uint32_t dstPitch = texture.m_width*bpp/8; + + uint32_t pitch = bx::uint32_min(srcPitch, dstPitch); + + for (uint32_t yy = 0, height = texture.m_height; yy < height; ++yy) + { + memcpy(dst, src, pitch); + + src += srcPitch; + dst += dstPitch; + } + + m_deviceCtx->Unmap(texture.m_ptr, 0); + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) BX_OVERRIDE { TextureD3D11& texture = m_textures[_handle.idx]; @@ -3903,11 +3930,12 @@ BX_PRAGMA_DIAGNOSTIC_POP(); } } - const bool bufferOnly = 0 != (m_flags&BGFX_TEXTURE_RT_BUFFER_ONLY); + const bool bufferOnly = 0 != (m_flags&(BGFX_TEXTURE_RT_BUFFER_ONLY|BGFX_TEXTURE_READ_BACK) ); const bool computeWrite = 0 != (m_flags&BGFX_TEXTURE_COMPUTE_WRITE); const bool renderTarget = 0 != (m_flags&BGFX_TEXTURE_RT_MASK); const bool srgb = 0 != (m_flags&BGFX_TEXTURE_SRGB) || imageContainer.m_srgb; const bool blit = 0 != (m_flags&BGFX_TEXTURE_BLIT_DST); + const bool readBack = 0 != (m_flags&BGFX_TEXTURE_READ_BACK); const uint32_t msaaQuality = bx::uint32_satsub( (m_flags&BGFX_TEXTURE_RT_MSAA_MASK)>>BGFX_TEXTURE_RT_MSAA_SHIFT, 1); const DXGI_SAMPLE_DESC& msaa = s_msaa[msaaQuality]; @@ -3966,6 +3994,13 @@ BX_PRAGMA_DIAGNOSTIC_POP(); desc.Usage = D3D11_USAGE_DEFAULT; } + if (readBack) + { + desc.BindFlags = 0; + desc.Usage = D3D11_USAGE_STAGING; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + } + if (imageContainer.m_cubeMap) { desc.ArraySize = 6; diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 7e2750ab2..5d194bba2 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -884,7 +884,7 @@ namespace bgfx { namespace d3d12 | BGFX_CAPS_COMPUTE | (m_options.ROVsSupported ? BGFX_CAPS_FRAGMENT_ORDERING : 0) // | BGFX_CAPS_SWAP_CHAIN - | BGFX_CAPS_BLIT + | BGFX_CAPS_TEXTURE_BLIT ); g_caps.maxTextureSize = 16384; g_caps.maxFBAttachments = uint8_t(bx::uint32_min(16, BGFX_CONFIG_MAX_FRAME_BUFFER_ATTACHMENTS) ); @@ -1250,6 +1250,10 @@ namespace bgfx { namespace d3d12 { } + void readTexture(TextureHandle /*_handle*/, void* /*_data*/) BX_OVERRIDE + { + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) BX_OVERRIDE { TextureD3D12& texture = m_textures[_handle.idx]; diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 0db3b6e69..d043090ce 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -535,7 +535,8 @@ namespace bgfx { namespace d3d9 | BGFX_CAPS_FRAGMENT_DEPTH | BGFX_CAPS_SWAP_CHAIN | ( (UINT16_MAX < m_caps.MaxVertexIndex) ? BGFX_CAPS_INDEX32 : 0) - | ( (m_caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) ? BGFX_CAPS_BLIT : 0) +// | ( (m_caps.DevCaps2 & D3DDEVCAPS2_CAN_STRETCHRECT_FROM_TEXTURES) ? BGFX_CAPS_TEXTURE_BLIT : 0) +// | BGFX_CAPS_TEXTURE_READ_BACK ); g_caps.maxTextureSize = uint16_t(bx::uint32_min(m_caps.MaxTextureWidth, m_caps.MaxTextureHeight) ); // g_caps.maxVertexIndex = m_caps.MaxVertexIndex; @@ -902,6 +903,37 @@ namespace bgfx { namespace d3d9 m_updateTexture = NULL; } + void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + { + TextureD3D9& texture = m_textures[_handle.idx]; + + D3DLOCKED_RECT lockedRect; + DX_CHECK(texture.m_texture2d->LockRect(0 + , &lockedRect + , NULL + , D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY + ) ); + + uint32_t srcPitch = lockedRect.Pitch; + uint8_t* src = (uint8_t*)lockedRect.pBits; + + const uint8_t bpp = getBitsPerPixel(TextureFormat::Enum(texture.m_textureFormat) ); + uint8_t* dst = (uint8_t*)_data; + uint32_t dstPitch = texture.m_width*bpp/8; + + uint32_t pitch = bx::uint32_min(srcPitch, dstPitch); + + for (uint32_t yy = 0, height = texture.m_height; yy < height; ++yy) + { + memcpy(dst, src, pitch); + + src += srcPitch; + dst += dstPitch; + } + + DX_CHECK(texture.m_texture2d->UnlockRect(0) ); + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) BX_OVERRIDE { TextureD3D9& texture = m_textures[_handle.idx]; diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 328c520e6..ac0e7807a 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -1204,6 +1204,7 @@ namespace bgfx { namespace gl , m_maxMsaa(0) , m_vao(0) , m_blitSupported(false) + , m_readBackSupported(false) , m_vaoSupport(false) , m_samplerObjectSupport(false) , m_shadowSamplersSupport(false) @@ -1713,7 +1714,7 @@ namespace bgfx { namespace gl { m_blitSupported = NULL != glCopyImageSubData; g_caps.supported |= m_blitSupported - ? BGFX_CAPS_BLIT + ? BGFX_CAPS_TEXTURE_BLIT : 0 ; } @@ -2093,6 +2094,36 @@ namespace bgfx { namespace gl { } + void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + { + if (m_readBackSupported) + { + const TextureGL& texture = m_textures[_handle.idx]; + const bool compressed = isCompressed(TextureFormat::Enum(texture.m_textureFormat) ); + + GL_CHECK(glBindTexture(texture.m_target, texture.m_id) ); + + if (compressed) + { + GL_CHECK(glGetCompressedTexImage(texture.m_target + , 0 + , _data + ) ); + } + else + { + GL_CHECK(glGetTexImage(texture.m_target + , 0 + , texture.m_fmt + , texture.m_type + , _data + ) ); + } + + GL_CHECK(glBindTexture(texture.m_target, 0) ); + } + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) BX_OVERRIDE { TextureGL& texture = m_textures[_handle.idx]; @@ -3106,6 +3137,7 @@ namespace bgfx { namespace gl int32_t m_maxMsaa; GLuint m_vao; bool m_blitSupported; + bool m_readBackSupported; bool m_vaoSupport; bool m_samplerObjectSupport; bool m_shadowSamplersSupport; diff --git a/src/renderer_mtl.mm b/src/renderer_mtl.mm index aa5fa04a4..8107e8d00 100644 --- a/src/renderer_mtl.mm +++ b/src/renderer_mtl.mm @@ -612,6 +612,10 @@ namespace bgfx { namespace mtl { } + void readTexture(TextureHandle /*_handle*/, void* /*_data*/) BX_OVERRIDE + { + } + void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height) BX_OVERRIDE { TextureMtl& texture = m_textures[_handle.idx]; diff --git a/src/renderer_null.cpp b/src/renderer_null.cpp index 5a86523fc..db6777bda 100644 --- a/src/renderer_null.cpp +++ b/src/renderer_null.cpp @@ -113,6 +113,10 @@ namespace bgfx { namespace noop { } + void readTexture(TextureHandle /*_handle*/, void* /*_data*/) BX_OVERRIDE + { + } + void resizeTexture(TextureHandle /*_handle*/, uint16_t /*_width*/, uint16_t /*_height*/) BX_OVERRIDE { }