diff --git a/include/bgfx/bgfx.h b/include/bgfx/bgfx.h index 8d2d6ea00..f60257b05 100644 --- a/include/bgfx/bgfx.h +++ b/include/bgfx/bgfx.h @@ -1824,7 +1824,7 @@ namespace bgfx /// @attention Availability depends on: `BGFX_CAPS_TEXTURE_READ_BACK`. /// @attention C99 equivalent is `bgfx_read_texture`. /// - uint32_t readTexture(TextureHandle _handle, void* _data); + uint32_t readTexture(TextureHandle _handle, void* _data, uint8_t _mip = 0); /// Read back texture content. /// diff --git a/src/bgfx.cpp b/src/bgfx.cpp index 0bb54a24c..38e34bfa2 100644 --- a/src/bgfx.cpp +++ b/src/bgfx.cpp @@ -2239,7 +2239,10 @@ namespace bgfx void* data; _cmdbuf.read(data); - m_renderCtx->readTexture(handle, data); + uint8_t mip; + _cmdbuf.read(mip); + + m_renderCtx->readTexture(handle, data,mip); } break; @@ -3208,12 +3211,12 @@ error: } } - uint32_t readTexture(TextureHandle _handle, void* _data) + uint32_t readTexture(TextureHandle _handle, void* _data, uint8_t _mip) { BGFX_CHECK_MAIN_THREAD(); BX_CHECK(NULL != _data, "_data can't be NULL"); BGFX_CHECK_CAPS(BGFX_CAPS_TEXTURE_READ_BACK, "Texture read-back is not supported!"); - return s_ctx->readTexture(_handle, _data); + return s_ctx->readTexture(_handle, _data, _mip); } uint32_t readTexture(FrameBufferHandle _handle, uint8_t _attachment, void* _data) diff --git a/src/bgfx_p.h b/src/bgfx_p.h index f4ab861bd..1aa10fe6e 100644 --- a/src/bgfx_p.h +++ b/src/bgfx_p.h @@ -2110,7 +2110,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 readTexture(TextureHandle _handle, void* _data, uint8_t _mip) = 0; virtual void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips) = 0; virtual void overrideInternal(TextureHandle _handle, uintptr_t _ptr) = 0; virtual uintptr_t getInternal(TextureHandle _handle) = 0; @@ -3202,11 +3202,12 @@ namespace bgfx textureDecRef(_handle); } - BGFX_API_FUNC(uint32_t readTexture(TextureHandle _handle, void* _data) ) + BGFX_API_FUNC(uint32_t readTexture(TextureHandle _handle, void* _data, uint8_t _mip) ) { CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ReadTexture); cmdbuf.write(_handle); cmdbuf.write(_data); + cmdbuf.write(_mip); return m_frames + 2; } @@ -3216,7 +3217,7 @@ namespace bgfx 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); - return readTexture(textureHandle, _data); + return readTexture(textureHandle, _data,0); } void resizeTexture(TextureHandle _handle, uint16_t _width, uint16_t _height, uint8_t _numMips) diff --git a/src/renderer_d3d11.cpp b/src/renderer_d3d11.cpp index c76fdda2c..98e7a9caa 100644 --- a/src/renderer_d3d11.cpp +++ b/src/renderer_d3d11.cpp @@ -1840,22 +1840,25 @@ BX_PRAGMA_DIAGNOSTIC_POP(); { } - void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) 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) ); + BX_CHECK(_mipMap(texture.m_ptr, _mip, D3D11_MAP_READ, 0, &mapped) ); - uint8_t* src = (uint8_t*)mapped.pData; - uint32_t srcPitch = mapped.RowPitch; + uint32_t srcWidth = texture.m_width>>_mip; + uint32_t srcHeight = texture.m_height>>_mip; + 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 dstPitch = srcWidth*bpp/8; uint32_t pitch = bx::uint32_min(srcPitch, dstPitch); - for (uint32_t yy = 0, height = texture.m_height; yy < height; ++yy) + for (uint32_t yy = 0, height = srcHeight; yy < height; ++yy) { memcpy(dst, src, pitch); diff --git a/src/renderer_d3d12.cpp b/src/renderer_d3d12.cpp index 4b0d22426..01d86879f 100644 --- a/src/renderer_d3d12.cpp +++ b/src/renderer_d3d12.cpp @@ -1401,8 +1401,9 @@ namespace bgfx { namespace d3d12 { } - void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip ) BX_OVERRIDE { + _mip; const TextureD3D12& texture = m_textures[_handle.idx]; D3D12_RESOURCE_DESC desc = texture.m_ptr->GetDesc(); diff --git a/src/renderer_d3d9.cpp b/src/renderer_d3d9.cpp index 529f9a6b0..abe7847f6 100644 --- a/src/renderer_d3d9.cpp +++ b/src/renderer_d3d9.cpp @@ -987,27 +987,30 @@ namespace bgfx { namespace d3d9 m_updateTexture = NULL; } - void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) BX_OVERRIDE { TextureD3D9& texture = m_textures[_handle.idx]; + BX_CHECK( _mipLockRect(0 + DX_CHECK(texture.m_texture2d->LockRect(_mip , &lockedRect , NULL , D3DLOCK_NO_DIRTY_UPDATE|D3DLOCK_NOSYSLOCK|D3DLOCK_READONLY ) ); - uint32_t srcPitch = lockedRect.Pitch; - uint8_t* src = (uint8_t*)lockedRect.pBits; + uint32_t srcWidth = texture.m_width>>_mip; + uint32_t srcHeight = texture.m_height>>_mip; + 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 dstPitch = srcWidth*bpp/8; uint32_t pitch = bx::uint32_min(srcPitch, dstPitch); - for (uint32_t yy = 0, height = texture.m_height; yy < height; ++yy) + for (uint32_t yy = 0, height = srcHeight; yy < height; ++yy) { memcpy(dst, src, pitch); diff --git a/src/renderer_gl.cpp b/src/renderer_gl.cpp index 07cfa44e1..73122fe74 100644 --- a/src/renderer_gl.cpp +++ b/src/renderer_gl.cpp @@ -2379,7 +2379,7 @@ namespace bgfx { namespace gl { } - void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) BX_OVERRIDE { if (m_readBackSupported) { @@ -2391,14 +2391,14 @@ namespace bgfx { namespace gl if (compressed) { GL_CHECK(glGetCompressedTexImage(texture.m_target - , 0 + , _mip , _data ) ); } else { GL_CHECK(glGetTexImage(texture.m_target - , 0 + , _mip , texture.m_fmt , texture.m_type , _data diff --git a/src/renderer_mtl.mm b/src/renderer_mtl.mm index 8f90bfcc3..7f67ac635 100644 --- a/src/renderer_mtl.mm +++ b/src/renderer_mtl.mm @@ -796,7 +796,7 @@ namespace bgfx { namespace mtl { } - void readTexture(TextureHandle _handle, void* _data) BX_OVERRIDE + void readTexture(TextureHandle _handle, void* _data, uint8_t _mip) BX_OVERRIDE { m_commandBuffer.commit(); m_commandBuffer.waitUntilCompleted(); @@ -804,13 +804,15 @@ namespace bgfx { namespace mtl const TextureMtl& texture = m_textures[_handle.idx]; - uint32_t width = texture.m_ptr.width(); - uint32_t height = texture.m_ptr.height(); + BX_CHECK(_mip> _mip; + uint32_t height = texture.m_ptr.height() >> _mip; const uint8_t bpp = getBitsPerPixel(TextureFormat::Enum(texture.m_textureFormat) ); MTLRegion region = { { 0, 0, 0 }, { width, height, 1 } }; - texture.m_ptr.getBytes(_data, width*bpp/8, 0, region, 0, 0); + texture.m_ptr.getBytes(_data, width*bpp/8, 0, region, _mip, 0); m_commandBuffer = m_commandQueue.commandBuffer(); retain(m_commandBuffer); //NOTE: keep alive to be useable at 'flip' diff --git a/src/renderer_noop.cpp b/src/renderer_noop.cpp index ca8ba170f..34a198d3a 100644 --- a/src/renderer_noop.cpp +++ b/src/renderer_noop.cpp @@ -136,7 +136,7 @@ namespace bgfx { namespace noop { } - void readTexture(TextureHandle /*_handle*/, void* /*_data*/) BX_OVERRIDE + void readTexture(TextureHandle /*_handle*/, void* /*_data*/, uint8_t /*_mip*/) BX_OVERRIDE { }