Compare commits

...
This repository has been archived on 2025-05-04. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.

5 commits

Author SHA1 Message Date
Christopher Willis-Ford
600c3a69e6 First pass implementation of readback for MTL renderer 2016-03-24 22:07:56 +00:00
Christopher Willis-Ford
737ad243a4 Call glBindFramebuffer after readback
This is a hack to fix an Android rendering problem. Calling
`setFrameBuffer` again to switch the binding back doesn't work; a proper
fix will take some more investigation.
2016-03-24 22:07:56 +00:00
Christopher Willis-Ford
f070f5b69c Don't call glReadBuffer on OpenGL ES
This call was already disabled for Emscripten, but it needs to be
disabled for all OpenGL ES platforms.
2016-03-24 22:07:56 +00:00
Christopher Willis-Ford
1c6775352b Implement texture readback in GL
Also rename the feature from `ReadBackTexture` to just `ReadBack`
2016-03-24 22:07:56 +00:00
Chris Willis-Ford
b9462febdb WIP texture read-back
Currently only implemented for D3D12. Some bugs present.
2016-03-24 22:07:56 +00:00
9 changed files with 205 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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() );

View file

@ -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)."

View file

@ -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) )

View file

@ -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
{
}

View file

@ -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) )

View file

@ -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]

View file

@ -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) )