Compare commits
5 commits
master
...
texture-re
Author | SHA1 | Date | |
---|---|---|---|
|
600c3a69e6 | ||
|
737ad243a4 | ||
|
f070f5b69c | ||
|
1c6775352b | ||
|
b9462febdb |
9 changed files with 205 additions and 0 deletions
|
@ -455,6 +455,13 @@ namespace bgfx
|
|||
/// @attention C99 equivalent is `bgfx_callback_vtbl.capture_frame`.
|
||||
///
|
||||
virtual void captureFrame(const void* _data, uint32_t _size) = 0;
|
||||
|
||||
/// Called when a texture is read back.
|
||||
///
|
||||
/// @param[in] _handle Texture that was read.
|
||||
/// @param[in] _data Image data.
|
||||
/// @param[in] _size Image size.
|
||||
virtual void readBack(FrameBufferHandle _handle, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t _size, bool _yflip) = 0;
|
||||
};
|
||||
|
||||
inline CallbackI::~CallbackI()
|
||||
|
@ -2733,6 +2740,17 @@ namespace bgfx
|
|||
///
|
||||
void saveScreenShot(const char* _filePath);
|
||||
|
||||
/// Read a texture back to the CPU.
|
||||
///
|
||||
/// @param[in] _handle Texture to read. Will be passed to `bgfx::CallbackI::readBack` callback.
|
||||
///
|
||||
/// @remarks
|
||||
/// `bgfx::CallbackI::screenShot` must be implemented.
|
||||
///
|
||||
/// @attention C99 equivalent is `bgfx_read_back_texture`.
|
||||
///
|
||||
void readBack(FrameBufferHandle _handle);
|
||||
|
||||
} // namespace bgfx
|
||||
|
||||
#endif // BGFX_H_HEADER_GUARD
|
||||
|
|
|
@ -435,6 +435,7 @@ typedef struct bgfx_callback_vtbl
|
|||
void (*capture_begin)(bgfx_callback_interface_t* _this, uint32_t _width, uint32_t _height, uint32_t _pitch, bgfx_texture_format_t _format, bool _yflip);
|
||||
void (*capture_end)(bgfx_callback_interface_t* _this);
|
||||
void (*capture_frame)(bgfx_callback_interface_t* _this, const void* _data, uint32_t _size);
|
||||
void (*read_back)(bgfx_callback_interface_t* _this, bgfx_frame_buffer_handle_t _handle, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t _size, bool _yflip);
|
||||
|
||||
} bgfx_callback_vtbl_t;
|
||||
|
||||
|
@ -839,4 +840,7 @@ BGFX_C_API void bgfx_blit_frame_buffer(uint8_t _id, bgfx_texture_handle_t _dst,
|
|||
/**/
|
||||
BGFX_C_API void bgfx_save_screen_shot(const char* _filePath);
|
||||
|
||||
/**/
|
||||
BGFX_C_API void bgfx_read_back_view(uint8_t _id);
|
||||
|
||||
#endif // BGFX_C99_H_HEADER_GUARD
|
||||
|
|
32
src/bgfx.cpp
32
src/bgfx.cpp
|
@ -135,6 +135,11 @@ namespace bgfx
|
|||
virtual void captureFrame(const void* /*_data*/, uint32_t /*_size*/) BX_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
||||
virtual void readBack(FrameBufferHandle /*_handle*/, uint32_t /*_width*/, uint32_t /*_height*/, uint32_t /*_pitch*/, const void* /*_data*/, uint32_t /*_size*/, bool /*_yflip*/) BX_OVERRIDE
|
||||
{
|
||||
BX_TRACE("Warning: using readback without callback (a.k.a. pointless).");
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef BGFX_CONFIG_MEMORY_TRACKING
|
||||
|
@ -2339,6 +2344,15 @@ namespace bgfx
|
|||
}
|
||||
break;
|
||||
|
||||
case CommandBuffer::ReadBack:
|
||||
{
|
||||
FrameBufferHandle handle;
|
||||
_cmdbuf.read(handle);
|
||||
|
||||
m_renderCtx->readBack(handle);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_CHECK(false, "Invalid command: %d", command);
|
||||
break;
|
||||
|
@ -3603,6 +3617,12 @@ namespace bgfx
|
|||
BGFX_CHECK_MAIN_THREAD();
|
||||
s_ctx->saveScreenShot(_filePath);
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle)
|
||||
{
|
||||
BGFX_CHECK_MAIN_THREAD();
|
||||
s_ctx->readBack(_handle);
|
||||
}
|
||||
} // namespace bgfx
|
||||
|
||||
#include <bgfx/c99/bgfx.h>
|
||||
|
@ -3716,6 +3736,12 @@ namespace bgfx
|
|||
m_interface->vtbl->capture_frame(m_interface, _data, _size);
|
||||
}
|
||||
|
||||
virtual void readBack(FrameBufferHandle _handle, uint32_t _width, uint32_t _height, uint32_t _pitch, const void* _data, uint32_t _size, bool _yflip) BX_OVERRIDE
|
||||
{
|
||||
union { bgfx_frame_buffer_handle_t c; bgfx::FrameBufferHandle cpp; } handle = { _handle.idx };
|
||||
m_interface->vtbl->read_back(m_interface, handle.c, _width, _height, _pitch, _data, _size, _yflip);
|
||||
}
|
||||
|
||||
bgfx_callback_interface_t* m_interface;
|
||||
};
|
||||
|
||||
|
@ -4522,6 +4548,12 @@ BGFX_C_API void bgfx_save_screen_shot(const char* _filePath)
|
|||
bgfx::saveScreenShot(_filePath);
|
||||
}
|
||||
|
||||
BGFX_C_API void bgfx_read_back(bgfx_frame_buffer_handle_t _handle)
|
||||
{
|
||||
union { bgfx_frame_buffer_handle_t c; bgfx::FrameBufferHandle cpp; } handle = { _handle };
|
||||
bgfx::readBack(handle.cpp);
|
||||
}
|
||||
|
||||
BGFX_C_API bgfx_render_frame_t bgfx_render_frame()
|
||||
{
|
||||
return bgfx_render_frame_t(bgfx::renderFrame() );
|
||||
|
|
|
@ -626,6 +626,7 @@ namespace bgfx
|
|||
DestroyUniform,
|
||||
ReadTexture,
|
||||
SaveScreenShot,
|
||||
ReadBack,
|
||||
};
|
||||
|
||||
void write(const void* _data, uint32_t _size)
|
||||
|
@ -2065,6 +2066,7 @@ namespace bgfx
|
|||
virtual void createUniform(UniformHandle _handle, UniformType::Enum _type, uint16_t _num, const char* _name) = 0;
|
||||
virtual void destroyUniform(UniformHandle _handle) = 0;
|
||||
virtual void saveScreenShot(const char* _filePath) = 0;
|
||||
virtual void readBack(FrameBufferHandle _handle) = 0;
|
||||
virtual void updateViewName(uint8_t _id, const char* _name) = 0;
|
||||
virtual void updateUniform(uint16_t _loc, const void* _data, uint32_t _size) = 0;
|
||||
virtual void setMarker(const char* _marker, uint32_t _size) = 0;
|
||||
|
@ -3430,6 +3432,12 @@ namespace bgfx
|
|||
cmdbuf.write(_filePath, len);
|
||||
}
|
||||
|
||||
BGFX_API_FUNC(void readBack(FrameBufferHandle _handle))
|
||||
{
|
||||
CommandBuffer& cmdbuf = getCommandBuffer(CommandBuffer::ReadBack);
|
||||
cmdbuf.write(_handle);
|
||||
}
|
||||
|
||||
BGFX_API_FUNC(void setPaletteColor(uint8_t _index, const float _rgba[4]) )
|
||||
{
|
||||
BX_CHECK(_index < BGFX_CONFIG_MAX_COLOR_PALETTE, "Color palette index out of bounds %d (max: %d)."
|
||||
|
|
|
@ -1961,6 +1961,11 @@ BX_PRAGMA_DIAGNOSTIC_POP();
|
|||
DX_RELEASE(backBuffer, 0);
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle) BX_OVERRIDE
|
||||
{
|
||||
g_callback->readBack(_handle, 0, 0, 0, NULL, 0, false);
|
||||
}
|
||||
|
||||
void updateViewName(uint8_t _id, const char* _name) BX_OVERRIDE
|
||||
{
|
||||
if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) )
|
||||
|
|
|
@ -1520,6 +1520,73 @@ namespace bgfx { namespace d3d12
|
|||
DX_RELEASE(readback, 0);
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle) BX_OVERRIDE
|
||||
{
|
||||
FrameBufferD3D12& framebuffer = m_frameBuffers[_handle.idx];
|
||||
|
||||
// TODO: allow access to others?
|
||||
TextureHandle textureHandle = framebuffer.m_texture[0];
|
||||
|
||||
TextureD3D12& texture = m_textures[textureHandle.idx];
|
||||
ID3D12Resource* resource = texture.m_ptr;
|
||||
D3D12_RESOURCE_DESC desc = resource->GetDesc();
|
||||
|
||||
const uint32_t width = (uint32_t)desc.Width;
|
||||
const uint32_t height = (uint32_t)desc.Height;
|
||||
|
||||
D3D12_PLACED_SUBRESOURCE_FOOTPRINT layout;
|
||||
uint32_t numRows;
|
||||
uint64_t total;
|
||||
uint64_t pitch;
|
||||
m_device->GetCopyableFootprints(&desc
|
||||
, 0
|
||||
, 1
|
||||
, 0
|
||||
, &layout
|
||||
, &numRows
|
||||
, &pitch
|
||||
, &total
|
||||
);
|
||||
|
||||
ID3D12Resource* readback = createCommittedResource(m_device, HeapProperty::ReadBack, total);
|
||||
|
||||
D3D12_BOX box;
|
||||
box.left = 0;
|
||||
box.top = 0;
|
||||
box.right = width;
|
||||
box.bottom = height;
|
||||
box.front = 0;
|
||||
box.back = 1;
|
||||
|
||||
setResourceBarrier(m_commandList, resource, D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_COPY_SOURCE);
|
||||
D3D12_TEXTURE_COPY_LOCATION dst = { readback, D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT,{ layout } };
|
||||
D3D12_TEXTURE_COPY_LOCATION src = { resource, D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,{} };
|
||||
m_commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, &box);
|
||||
setResourceBarrier(m_commandList, resource, D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_PRESENT);
|
||||
finish();
|
||||
m_commandList = m_cmd.alloc();
|
||||
|
||||
void* data;
|
||||
readback->Map(0, NULL, (void**)&data);
|
||||
imageSwizzleBgra8(width
|
||||
, height
|
||||
, (uint32_t)pitch
|
||||
, data
|
||||
, data
|
||||
);
|
||||
g_callback->readBack(_handle
|
||||
, width
|
||||
, height
|
||||
, (uint32_t)layout.Footprint.RowPitch // TODO: figure out pitch inconsistency
|
||||
, data
|
||||
, (uint32_t)total
|
||||
, false
|
||||
);
|
||||
readback->Unmap(0, NULL);
|
||||
|
||||
DX_RELEASE(readback, 0);
|
||||
}
|
||||
|
||||
void updateViewName(uint8_t /*_id*/, const char* /*_name*/) BX_OVERRIDE
|
||||
{
|
||||
}
|
||||
|
|
|
@ -1156,6 +1156,11 @@ namespace bgfx { namespace d3d9
|
|||
#endif // BX_PLATFORM_WINDOWS
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle) BX_OVERRIDE
|
||||
{
|
||||
g_callback->readBack(_handle, 0, 0, 0, NULL, 0, false);
|
||||
}
|
||||
|
||||
void updateViewName(uint8_t _id, const char* _name) BX_OVERRIDE
|
||||
{
|
||||
if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) )
|
||||
|
|
|
@ -2340,6 +2340,46 @@ namespace bgfx { namespace gl
|
|||
BX_FREE(g_allocator, data);
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle) BX_OVERRIDE
|
||||
{
|
||||
const FrameBufferGL& framebuffer = m_frameBuffers[_handle.idx];
|
||||
|
||||
const uint32_t width = framebuffer.m_width;
|
||||
const uint32_t height = framebuffer.m_height;
|
||||
|
||||
const uint32_t length = width * height * 4;
|
||||
uint8_t* const data = (uint8_t*)BX_ALLOC(g_allocator, length);
|
||||
|
||||
setFrameBuffer(_handle, height);
|
||||
GL_CHECK(glViewport(0, 0, width, height));
|
||||
|
||||
# if !BGFX_CONFIG_RENDERER_OPENGLES
|
||||
// OpenGL ES doesn't support glReadBuffer but it's necessary elsewhere
|
||||
GL_CHECK(glReadBuffer(GL_COLOR_ATTACHMENT0));
|
||||
# endif
|
||||
|
||||
GL_CHECK(glReadPixels(0
|
||||
, 0
|
||||
, width
|
||||
, height
|
||||
, m_readPixelsFmt
|
||||
, GL_UNSIGNED_BYTE
|
||||
, data
|
||||
));
|
||||
|
||||
if (GL_RGBA == m_readPixelsFmt)
|
||||
{
|
||||
imageSwizzleBgra8(width, height, width * 4, data, data);
|
||||
}
|
||||
|
||||
g_callback->readBack(_handle, width, height, width * 4, data, length, true);
|
||||
|
||||
// TODO: this call to glBindFramebuffer shouldn't be here
|
||||
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, 0) );
|
||||
|
||||
BX_FREE(g_allocator, data);
|
||||
}
|
||||
|
||||
void updateViewName(uint8_t _id, const char* _name) BX_OVERRIDE
|
||||
{
|
||||
bx::strlcpy(&s_viewName[_id][BGFX_CONFIG_MAX_VIEW_NAME_RESERVED]
|
||||
|
|
|
@ -773,6 +773,32 @@ namespace bgfx { namespace mtl
|
|||
BX_FREE(g_allocator, data);
|
||||
}
|
||||
|
||||
void readBack(FrameBufferHandle _handle) BX_OVERRIDE
|
||||
{
|
||||
const FrameBufferMtl &framebuffer = m_frameBuffers[_handle.idx];
|
||||
const TextureHandle handle = framebuffer.m_colorHandle[0];
|
||||
|
||||
if (isValid(handle))
|
||||
{
|
||||
Texture &texture = m_textures[handle.idx].m_ptr;
|
||||
|
||||
const uint32_t width = framebuffer.m_width;
|
||||
const uint32_t height = framebuffer.m_height;
|
||||
const uint32_t stride = 4 * width;
|
||||
const uint32_t length = stride * height;
|
||||
|
||||
uint8_t *const data = (uint8_t *) BX_ALLOC(g_allocator, length);
|
||||
|
||||
const MTLRegion region = {{0, 0, 0}, {width, height, 1}};
|
||||
|
||||
texture.getBytes(data, stride, 0, region, 0, 0);
|
||||
|
||||
g_callback->readBack(_handle, width, height, stride, data, length, true);
|
||||
|
||||
BX_FREE(g_allocator, data);
|
||||
}
|
||||
}
|
||||
|
||||
void updateViewName(uint8_t _id, const char* _name) BX_OVERRIDE
|
||||
{
|
||||
if (BX_ENABLED(BGFX_CONFIG_DEBUG_PIX) )
|
||||
|
|
Reference in a new issue