Skip to content

Commit 0192d8e

Browse files
committed
[Olympus] Allow GPU Buffer upload and download (#11)
- add create and destroy callback to buffer object - allow read pixels into buffer object without downloading from CPU - allow upload textures data using buffer objects - add gpu thread callback note only the openGl api has been implemented for these
1 parent 4260019 commit 0192d8e

26 files changed

+400
-4
lines changed

filament/backend/include/backend/DriverEnums.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,9 @@ enum class ElementType : uint8_t {
290290
//! Buffer object binding type
291291
enum class BufferObjectBinding : uint8_t {
292292
VERTEX,
293-
UNIFORM
293+
UNIFORM,
294+
PIXEL_DOWNLOAD,
295+
PIXEL_UPLOAD
294296
};
295297

296298
//! Face culling Mode
@@ -1021,6 +1023,8 @@ using FrameScheduledCallback = void(*)(PresentCallable callable, void* user);
10211023

10221024
using FrameCompletedCallback = void(*)(void* user);
10231025

1026+
using GPUBufferCallback = void(*)(void* buffer, size_t size, void* user);
1027+
10241028
enum class Workaround : uint16_t {
10251029
// The EASU pass must split because shader compiler flattens early-exit branch
10261030
SPLIT_EASU,

filament/backend/include/private/backend/DriverAPI.inc

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,16 @@ DECL_DRIVER_API_SYNCHRONOUS_N(bool, isWorkaroundNeeded, backend::Workaround, wor
310310
* -----------------------
311311
*/
312312

313+
DECL_DRIVER_API_N(getBufferObjectHwResource,
314+
backend::BufferObjectHandle, boh,
315+
backend::GPUBufferCallback, callback,
316+
void*, user)
317+
318+
DECL_DRIVER_API_N(getBufferData,
319+
backend::BufferObjectHandle, boh,
320+
backend::BufferDescriptor&&, data,
321+
uint32_t, byteOffset)
322+
313323
DECL_DRIVER_API_N(setVertexBufferObject,
314324
backend::VertexBufferHandle, vbh,
315325
uint32_t, index,
@@ -346,6 +356,16 @@ DECL_DRIVER_API_N(update2DImage,
346356
uint32_t, height,
347357
backend::PixelBufferDescriptor&&, data)
348358

359+
DECL_DRIVER_API_N(update2DImageWithBuffer,
360+
backend::TextureHandle, th,
361+
uint32_t, level,
362+
uint32_t, xoffset,
363+
uint32_t, yoffset,
364+
uint32_t, width,
365+
uint32_t, height,
366+
backend::BufferObjectHandle, boh,
367+
backend::PixelBufferDescriptor&&, data)
368+
349369
DECL_DRIVER_API_N(setMinMaxLevels,
350370
backend::TextureHandle, th,
351371
uint32_t, minLevel,
@@ -458,6 +478,15 @@ DECL_DRIVER_API_N(readPixels,
458478
uint32_t, height,
459479
backend::PixelBufferDescriptor&&, data)
460480

481+
DECL_DRIVER_API_N(readPixelsToBuffer,
482+
backend::RenderTargetHandle, src,
483+
uint32_t, x,
484+
uint32_t, y,
485+
uint32_t, width,
486+
uint32_t, height,
487+
backend::BufferObjectHandle, boh,
488+
backend::PixelBufferDescriptor&&, data)
489+
461490
/*
462491
* Rendering operations
463492
* --------------------

filament/backend/src/noop/NoopDriver.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ void NoopDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh, Bu
203203
void NoopDriver::resetBufferObject(Handle<HwBufferObject> boh) {
204204
}
205205

206+
void NoopDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
207+
backend::GPUBufferCallback callback, void* user) {
208+
}
209+
210+
void NoopDriver::getBufferData(Handle<HwBufferObject> boh,
211+
BufferDescriptor&& bd, uint32_t byteOffset) {
212+
}
213+
206214
void NoopDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
207215
Handle<HwBufferObject> boh) {
208216
}
@@ -213,6 +221,11 @@ void NoopDriver::update2DImage(Handle<HwTexture> th,
213221
scheduleDestroy(std::move(data));
214222
}
215223

224+
void NoopDriver::update2DImageWithBuffer(Handle<HwTexture> th,
225+
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
226+
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
227+
}
228+
216229
void NoopDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint32_t maxLevel) {
217230
}
218231

@@ -307,6 +320,12 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
307320
scheduleDestroy(std::move(p));
308321
}
309322

323+
void NoopDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
324+
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
325+
backend::BufferObjectHandle boh,
326+
PixelBufferDescriptor&& p) {
327+
}
328+
310329
void NoopDriver::blit(TargetBufferFlags buffers,
311330
Handle<HwRenderTarget> dst, Viewport dstRect,
312331
Handle<HwRenderTarget> src, Viewport srcRect,

filament/backend/src/opengl/GLUtils.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,10 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no
119119
return GL_ARRAY_BUFFER;
120120
case BufferObjectBinding::UNIFORM:
121121
return GL_UNIFORM_BUFFER;
122+
case BufferObjectBinding::PIXEL_DOWNLOAD:
123+
return GL_PIXEL_PACK_BUFFER;
124+
case BufferObjectBinding::PIXEL_UPLOAD:
125+
return GL_PIXEL_UNPACK_BUFFER;
122126
}
123127
}
124128

filament/backend/src/opengl/OpenGLDriver.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
428428
glGenBuffers(1, &bo->gl.id);
429429
gl.bindBuffer(bo->gl.binding, bo->gl.id);
430430
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
431+
gl.bindBuffer(bo->gl.binding, 0);
431432
CHECK_GL_ERROR(utils::slog.e)
432433
}
433434

@@ -1621,6 +1622,29 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
16211622
// Updating driver objects
16221623
// ------------------------------------------------------------------------------------------------
16231624

1625+
void OpenGLDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
1626+
GPUBufferCallback callback, void* user) {
1627+
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
1628+
void* hwResource = &(bo->gl.id);
1629+
callback(hwResource, bo->byteCount, user);
1630+
}
1631+
1632+
void OpenGLDriver::getBufferData(Handle<HwBufferObject> boh,
1633+
BufferDescriptor&& bd, uint32_t byteOffset) {
1634+
DEBUG_MARKER()
1635+
auto& gl = mContext;
1636+
1637+
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
1638+
GLuint pbo = bo->gl.id;
1639+
gl.bindBuffer(bo->gl.binding, pbo);
1640+
void* vaddr = glMapBufferRange(bo->gl.binding, byteOffset, bd.size, GL_MAP_READ_BIT);
1641+
memcpy(bd.buffer, vaddr, bd.size);
1642+
glUnmapBuffer(bo->gl.binding);
1643+
gl.bindBuffer(bo->gl.binding, 0);
1644+
1645+
CHECK_GL_ERROR(utils::slog.e)
1646+
}
1647+
16241648
void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
16251649
uint32_t index, Handle<HwBufferObject> boh) {
16261650
DEBUG_MARKER()
@@ -1764,6 +1788,24 @@ void OpenGLDriver::update2DImage(Handle<HwTexture> th,
17641788
}
17651789
}
17661790

1791+
void OpenGLDriver::update2DImageWithBuffer(Handle<HwTexture> th,
1792+
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
1793+
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
1794+
DEBUG_MARKER()
1795+
auto& gl = mContext;
1796+
1797+
GLTexture* t = handle_cast<GLTexture *>(th);
1798+
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
1799+
1800+
GLuint pbo = bo->gl.id;
1801+
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
1802+
1803+
setTextureData(t, level, xoffset, yoffset, 0, width, height, 1, std::move(data), nullptr);
1804+
1805+
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
1806+
CHECK_GL_ERROR(utils::slog.e)
1807+
}
1808+
17671809
void OpenGLDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint32_t maxLevel) {
17681810
DEBUG_MARKER()
17691811
auto& gl = mContext;
@@ -2567,6 +2609,33 @@ void OpenGLDriver::stopCapture(int) {
25672609
// Read-back ops
25682610
// ------------------------------------------------------------------------------------------------
25692611

2612+
void OpenGLDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
2613+
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
2614+
backend::BufferObjectHandle boh,
2615+
PixelBufferDescriptor&& p) {
2616+
DEBUG_MARKER()
2617+
auto& gl = mContext;
2618+
2619+
GLenum glFormat = getFormat(p.format);
2620+
GLenum glType = getType(p.type);
2621+
2622+
GLRenderTarget const* s = handle_cast<GLRenderTarget const*>(src);
2623+
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, s->gl.fbo);
2624+
2625+
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
2626+
GLuint pbo = bo->gl.id;
2627+
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
2628+
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, nullptr);
2629+
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
2630+
CHECK_GL_ERROR(utils::slog.e)
2631+
2632+
auto* pUserBuffer = new PixelBufferDescriptor(std::move(p));
2633+
whenGpuCommandsComplete([pbo, pUserBuffer]() mutable {
2634+
pUserBuffer->buffer = &pbo;
2635+
delete pUserBuffer;
2636+
});
2637+
}
2638+
25702639
void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
25712640
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
25722641
PixelBufferDescriptor&& p) {

filament/backend/src/ostream.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ io::ostream& operator<<(io::ostream& out, BufferObjectBinding binding) {
367367
switch (binding) {
368368
CASE(BufferObjectBinding, VERTEX)
369369
CASE(BufferObjectBinding, UNIFORM)
370+
CASE(BufferObjectBinding, PIXEL_DOWNLOAD)
371+
CASE(BufferObjectBinding, PIXEL_UPLOAD)
370372
}
371373
return out;
372374
}

filament/backend/src/vulkan/VulkanDriver.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,6 +889,14 @@ uint8_t VulkanDriver::getMaxDrawBuffers() {
889889
return MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; // TODO: query real value
890890
}
891891

892+
void VulkanDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
893+
backend::GPUBufferCallback callback, void* user) {
894+
}
895+
896+
void VulkanDriver::getBufferData(Handle<HwBufferObject> boh,
897+
BufferDescriptor&& bd, uint32_t byteOffset) {
898+
}
899+
892900
void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
893901
Handle<HwBufferObject> boh) {
894902
auto& vb = *handle_cast<VulkanVertexBuffer*>(vbh);
@@ -939,6 +947,11 @@ void VulkanDriver::update2DImage(Handle<HwTexture> th,
939947
scheduleDestroy(std::move(data));
940948
}
941949

950+
void VulkanDriver::update2DImageWithBuffer(Handle<HwTexture> th,
951+
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t width, uint32_t height,
952+
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
953+
}
954+
942955
void VulkanDriver::setMinMaxLevels(Handle<HwTexture> th, uint32_t minLevel, uint32_t maxLevel) {
943956
handle_cast<VulkanTexture*>(th)->setPrimaryRange(minLevel, maxLevel);
944957
}
@@ -1662,6 +1675,12 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
16621675
scheduleDestroy(std::move(pbd));
16631676
}
16641677

1678+
void VulkanDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
1679+
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
1680+
backend::BufferObjectHandle boh,
1681+
PixelBufferDescriptor&& p) {
1682+
}
1683+
16651684
void VulkanDriver::blit(TargetBufferFlags buffers, Handle<HwRenderTarget> dst, Viewport dstRect,
16661685
Handle<HwRenderTarget> src, Viewport srcRect, SamplerMagFilter filter) {
16671686
assert_invariant(mContext.currentRenderPass.renderPass == VK_NULL_HANDLE);

filament/backend/src/vulkan/VulkanHandles.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,8 @@ inline constexpr VkBufferUsageFlagBits getBufferObjectUsage(
139139
return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
140140
case BufferObjectBinding::UNIFORM:
141141
return VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
142+
default:
143+
return {};
142144
// when adding more buffer types here, make sure to update VulkanBuffer::loadFromCpu()
143145
// if necessary.
144146
}

filament/include/filament/BufferObject.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class UTILS_PUBLIC BufferObject : public FilamentAPI {
5151
public:
5252
using BufferDescriptor = backend::BufferDescriptor;
5353
using BindingType = backend::BufferObjectBinding;
54+
using BufferUsage = backend::BufferUsage;
55+
using CreateCallback = backend::GPUBufferCallback;
56+
using DestroyCallback = backend::GPUBufferCallback;
5457

5558
class Builder : public BuilderBase<BuilderDetails> {
5659
friend struct BuilderDetails;
@@ -76,6 +79,31 @@ class UTILS_PUBLIC BufferObject : public FilamentAPI {
7679
*/
7780
Builder& bindingType(BindingType bindingType) noexcept;
7881

82+
/**
83+
* The usage type for this buffer object. (defaults to STATIC)
84+
* @param bufferUsage Static, Dynamic or Stream.
85+
* @return A reference to this Builder for chaining calls.
86+
*/
87+
Builder& bufferUsage(BufferUsage bufferUsage) noexcept;
88+
89+
/**
90+
* Set a callback to be run on the driver thread when the buffer object got
91+
* created.
92+
* @param callback user callback.
93+
* @param user pointer for passing user data to callback.
94+
* @return A reference to this Builder for chaining calls.
95+
*/
96+
Builder& createCallback(CreateCallback callback, void* user) noexcept;
97+
98+
/**
99+
* Set a callback to be run on the driver thread when the buffer object got
100+
* created.
101+
* @param callback user callback.
102+
* @param user pointer for passing user data to callback.
103+
* @return A reference to this Builder for chaining calls.
104+
*/
105+
Builder& destroyCallback(DestroyCallback callback, void* user) noexcept;
106+
79107
/**
80108
* Creates the BufferObject and returns a pointer to it. After creation, the buffer
81109
* object is uninitialized. Use BufferObject::setBuffer() to initialize it.
@@ -105,6 +133,15 @@ class UTILS_PUBLIC BufferObject : public FilamentAPI {
105133
*/
106134
void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
107135

136+
/**
137+
* Asynchronously copy back a region of this BufferObject from GPU.
138+
*
139+
* @param engine Reference to the filament::Engine associated with this BufferObject.
140+
* @param buffer A BufferDescriptor that will hold the data copied back from GPU.
141+
* @param byteOffset Offset in bytes into the BufferObject
142+
*/
143+
void getBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);
144+
108145
/**
109146
* Returns the size of this BufferObject in elements.
110147
* @return The maximum capacity of the BufferObject.

filament/include/filament/Engine.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class UTILS_PUBLIC Engine {
151151
public:
152152
using Platform = backend::Platform;
153153
using Backend = backend::Backend;
154+
using Command = std::function<void()>;
154155

155156
/**
156157
* Creates an instance of Engine
@@ -537,6 +538,13 @@ class UTILS_PUBLIC Engine {
537538
*/
538539
void execute();
539540

541+
/**
542+
* Schedule a command to be run on the driver thread.
543+
*
544+
* @param command a command to be ran on the driver thread.
545+
*/
546+
void queueCommand(Command command);
547+
540548
/**
541549
* Retrieves the job system that the Engine has ownership over.
542550
*

0 commit comments

Comments
 (0)