Skip to content

Commit

Permalink
[Olympus] Allow GPU Buffer upload and download (google#11)
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
zbai-sc committed Nov 20, 2022
1 parent e2646a8 commit 136bb9b
Show file tree
Hide file tree
Showing 26 changed files with 441 additions and 4 deletions.
6 changes: 5 additions & 1 deletion filament/backend/include/backend/DriverEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,9 @@ enum class ElementType : uint8_t {
enum class BufferObjectBinding : uint8_t {
VERTEX,
UNIFORM,
SHADER_STORAGE
SHADER_STORAGE,
PIXEL_DOWNLOAD,
PIXEL_UPLOAD
};

//! Face culling Mode
Expand Down Expand Up @@ -1045,6 +1047,8 @@ using FrameScheduledCallback = void(*)(PresentCallable callable, void* user);

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

using GPUBufferCallback = void(*)(void* buffer, size_t size, void* user);

enum class Workaround : uint16_t {
// The EASU pass must split because shader compiler flattens early-exit branch
SPLIT_EASU,
Expand Down
31 changes: 31 additions & 0 deletions filament/backend/include/private/backend/DriverAPI.inc
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@ DECL_DRIVER_API_SYNCHRONOUS_0(backend::FeatureLevel, getFeatureLevel)
* -----------------------
*/

DECL_DRIVER_API_N(getBufferObjectHwResource,
backend::BufferObjectHandle, boh,
backend::GPUBufferCallback, callback,
void*, user)

DECL_DRIVER_API_N(getBufferData,
backend::BufferObjectHandle, boh,
backend::BufferDescriptor&&, data,
uint32_t, byteOffset)

DECL_DRIVER_API_N(setVertexBufferObject,
backend::VertexBufferHandle, vbh,
uint32_t, index,
Expand Down Expand Up @@ -357,6 +367,18 @@ DECL_DRIVER_API_N(update3DImage,
uint32_t, depth,
backend::PixelBufferDescriptor&&, data)

DECL_DRIVER_API_N(update3DImageWithBuffer,
backend::TextureHandle, th,
uint32_t, level,
uint32_t, xoffset,
uint32_t, yoffset,
uint32_t, zoffset,
uint32_t, width,
uint32_t, height,
uint32_t, depth,
backend::BufferObjectHandle, boh,
backend::PixelBufferDescriptor&&, data)

DECL_DRIVER_API_N(generateMipmaps,
backend::TextureHandle, th)

Expand Down Expand Up @@ -452,6 +474,15 @@ DECL_DRIVER_API_N(readPixels,
uint32_t, height,
backend::PixelBufferDescriptor&&, data)

DECL_DRIVER_API_N(readPixelsToBuffer,
backend::RenderTargetHandle, src,
uint32_t, x,
uint32_t, y,
uint32_t, width,
uint32_t, height,
backend::BufferObjectHandle, boh,
backend::PixelBufferDescriptor&&, data)

DECL_DRIVER_API_N(readBufferSubData,
backend::BufferObjectHandle, src,
uint32_t, offset,
Expand Down
21 changes: 21 additions & 0 deletions filament/backend/src/noop/NoopDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,14 @@ void NoopDriver::updateBufferObjectUnsynchronized(Handle<HwBufferObject> ibh, Bu
void NoopDriver::resetBufferObject(Handle<HwBufferObject> boh) {
}

void NoopDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
backend::GPUBufferCallback callback, void* user) {
}

void NoopDriver::getBufferData(Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset) {
}

void NoopDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
Handle<HwBufferObject> boh) {
}
Expand All @@ -221,6 +229,13 @@ void NoopDriver::update3DImage(Handle<HwTexture> th,
scheduleDestroy(std::move(data));
}

void NoopDriver::update3DImageWithBuffer(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
scheduleDestroy(std::move(data));
}

void NoopDriver::setupExternalImage(void* image) {
}

Expand Down Expand Up @@ -304,6 +319,12 @@ void NoopDriver::readPixels(Handle<HwRenderTarget> src,
scheduleDestroy(std::move(p));
}

void NoopDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
backend::BufferObjectHandle boh, PixelBufferDescriptor&& p) {
scheduleDestroy(std::move(p));
}

void NoopDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
scheduleDestroy(std::move(p));
Expand Down
4 changes: 4 additions & 0 deletions filament/backend/src/opengl/GLUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ constexpr inline GLenum getBufferBindingType(BufferObjectBinding bindingType) no
return GL_UNIFORM_BUFFER;
case BufferObjectBinding::SHADER_STORAGE:
return GL_SHADER_STORAGE_BUFFER;
case BufferObjectBinding::PIXEL_DOWNLOAD:
return GL_PIXEL_PACK_BUFFER;
case BufferObjectBinding::PIXEL_UPLOAD:
return GL_PIXEL_UNPACK_BUFFER;
}
}

Expand Down
80 changes: 80 additions & 0 deletions filament/backend/src/opengl/OpenGLDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,7 @@ void OpenGLDriver::createBufferObjectR(Handle<HwBufferObject> boh,
glGenBuffers(1, &bo->gl.id);
gl.bindBuffer(bo->gl.binding, bo->gl.id);
glBufferData(bo->gl.binding, byteCount, nullptr, getBufferUsage(usage));
gl.bindBuffer(bo->gl.binding, 0);
CHECK_GL_ERROR(utils::slog.e)
}

Expand Down Expand Up @@ -1685,6 +1686,29 @@ void OpenGLDriver::makeCurrent(Handle<HwSwapChain> schDraw, Handle<HwSwapChain>
// Updating driver objects
// ------------------------------------------------------------------------------------------------

void OpenGLDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
GPUBufferCallback callback, void* user) {
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
void* hwResource = &(bo->gl.id);
callback(hwResource, bo->byteCount, user);
}

void OpenGLDriver::getBufferData(Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset) {
DEBUG_MARKER()
auto& gl = mContext;

GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
GLuint pbo = bo->gl.id;
gl.bindBuffer(bo->gl.binding, pbo);
void* vaddr = glMapBufferRange(bo->gl.binding, byteOffset, bd.size, GL_MAP_READ_BIT);
memcpy(bd.buffer, vaddr, bd.size);
glUnmapBuffer(bo->gl.binding);
gl.bindBuffer(bo->gl.binding, 0);

CHECK_GL_ERROR(utils::slog.e)
}

void OpenGLDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh,
uint32_t index, Handle<HwBufferObject> boh) {
DEBUG_MARKER()
Expand Down Expand Up @@ -1903,6 +1927,30 @@ void OpenGLDriver::update3DImage(Handle<HwTexture> th,
}
}

void OpenGLDriver::update3DImageWithBuffer(Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
DEBUG_MARKER()

auto& gl = mContext;
GLTexture* t = handle_cast<GLTexture *>(th);
GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);

GLuint pbo = bo->gl.id;
gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);

if (data.type == PixelDataType::COMPRESSED) {
setCompressedTextureData(t,
level, xoffset, yoffset, zoffset, width, height, depth, std::move(data));
} else {
setTextureData(t,
level, xoffset, yoffset, zoffset, width, height, depth, std::move(data));
}

gl.bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
}

void OpenGLDriver::generateMipmaps(Handle<HwTexture> th) {
DEBUG_MARKER()

Expand Down Expand Up @@ -2778,6 +2826,38 @@ void OpenGLDriver::readPixels(Handle<HwRenderTarget> src,
});
}

void OpenGLDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
backend::BufferObjectHandle boh,
PixelBufferDescriptor&& p) {
DEBUG_MARKER()
auto& gl = mContext;

GLenum glFormat = getFormat(p.format);
GLenum glType = getType(p.type);

gl.pixelStore(GL_PACK_ROW_LENGTH, (GLint)p.stride);
gl.pixelStore(GL_PACK_ALIGNMENT, (GLint)p.alignment);
gl.pixelStore(GL_PACK_SKIP_PIXELS, (GLint)p.left);
gl.pixelStore(GL_PACK_SKIP_ROWS, (GLint)p.top);

GLRenderTarget const* s = handle_cast<GLRenderTarget const*>(src);
gl.bindFramebuffer(GL_READ_FRAMEBUFFER, s->gl.fbo);

GLBufferObject* bo = handle_cast<GLBufferObject *>(boh);
GLuint pbo = bo->gl.id;
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glReadPixels(GLint(x), GLint(y), GLint(width), GLint(height), glFormat, glType, nullptr);
gl.bindBuffer(GL_PIXEL_PACK_BUFFER, 0);
CHECK_GL_ERROR(utils::slog.e)

auto* pUserBuffer = new PixelBufferDescriptor(std::move(p));
whenGpuCommandsComplete([pbo, pUserBuffer]() mutable {
pUserBuffer->buffer = &pbo;
delete pUserBuffer;
});
}

void OpenGLDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
auto& gl = mContext;
Expand Down
2 changes: 2 additions & 0 deletions filament/backend/src/ostream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,8 @@ io::ostream& operator<<(io::ostream& out, BufferObjectBinding binding) {
CASE(BufferObjectBinding, VERTEX)
CASE(BufferObjectBinding, UNIFORM)
CASE(BufferObjectBinding, SHADER_STORAGE)
CASE(BufferObjectBinding, PIXEL_DOWNLOAD)
CASE(BufferObjectBinding, PIXEL_UPLOAD)
}
return out;
}
Expand Down
22 changes: 22 additions & 0 deletions filament/backend/src/vulkan/VulkanDriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -920,6 +920,14 @@ uint8_t VulkanDriver::getMaxDrawBuffers() {
return MRT::MIN_SUPPORTED_RENDER_TARGET_COUNT; // TODO: query real value
}

void VulkanDriver::getBufferObjectHwResource(Handle<HwBufferObject> boh,
backend::GPUBufferCallback callback, void* user) {
}

void VulkanDriver::getBufferData(Handle<HwBufferObject> boh,
BufferDescriptor&& bd, uint32_t byteOffset) {
}

void VulkanDriver::setVertexBufferObject(Handle<HwVertexBuffer> vbh, uint32_t index,
Handle<HwBufferObject> boh) {
auto& vb = *handle_cast<VulkanVertexBuffer*>(vbh);
Expand Down Expand Up @@ -976,6 +984,14 @@ void VulkanDriver::update3DImage(
scheduleDestroy(std::move(data));
}

void VulkanDriver::update3DImageWithBuffer(
Handle<HwTexture> th,
uint32_t level, uint32_t xoffset, uint32_t yoffset, uint32_t zoffset,
uint32_t width, uint32_t height, uint32_t depth,
Handle<HwBufferObject> boh, PixelBufferDescriptor&& data) {
scheduleDestroy(std::move(data));
}

void VulkanDriver::setupExternalImage(void* image) {
}

Expand Down Expand Up @@ -1700,6 +1716,12 @@ void VulkanDriver::readPixels(Handle<HwRenderTarget> src, uint32_t x, uint32_t y
scheduleDestroy(std::move(pbd));
}

void VulkanDriver::readPixelsToBuffer(Handle<HwRenderTarget> src,
uint32_t x, uint32_t y, uint32_t width, uint32_t height,
backend::BufferObjectHandle boh, PixelBufferDescriptor&& p) {
scheduleDestroy(std::move(p));
}

void VulkanDriver::readBufferSubData(backend::BufferObjectHandle boh,
uint32_t offset, uint32_t size, backend::BufferDescriptor&& p) {
// TODO: implement readBufferSubData
Expand Down
2 changes: 2 additions & 0 deletions filament/backend/src/vulkan/VulkanHandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ inline constexpr VkBufferUsageFlagBits getBufferObjectUsage(
return VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
// when adding more buffer-types here, make sure to update VulkanBuffer::loadFromCpu()
// if necessary.
default:
return {};
}
}

Expand Down
37 changes: 37 additions & 0 deletions filament/include/filament/BufferObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class UTILS_PUBLIC BufferObject : public FilamentAPI {
public:
using BufferDescriptor = backend::BufferDescriptor;
using BindingType = backend::BufferObjectBinding;
using BufferUsage = backend::BufferUsage;
using CreateCallback = backend::GPUBufferCallback;
using DestroyCallback = backend::GPUBufferCallback;

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

/**
* The usage type for this buffer object. (defaults to STATIC)
* @param bufferUsage Static, Dynamic or Stream.
* @return A reference to this Builder for chaining calls.
*/
Builder& bufferUsage(BufferUsage bufferUsage) noexcept;

/**
* Set a callback to be run on the driver thread when the buffer object got
* created.
* @param callback user callback.
* @param user pointer for passing user data to callback.
* @return A reference to this Builder for chaining calls.
*/
Builder& createCallback(CreateCallback callback, void* user) noexcept;

/**
* Set a callback to be run on the driver thread when the buffer object got
* created.
* @param callback user callback.
* @param user pointer for passing user data to callback.
* @return A reference to this Builder for chaining calls.
*/
Builder& destroyCallback(DestroyCallback callback, void* user) noexcept;

/**
* Creates the BufferObject and returns a pointer to it. After creation, the buffer
* object is uninitialized. Use BufferObject::setBuffer() to initialize it.
Expand Down Expand Up @@ -105,6 +133,15 @@ class UTILS_PUBLIC BufferObject : public FilamentAPI {
*/
void setBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);

/**
* Asynchronously copy back a region of this BufferObject from GPU.
*
* @param engine Reference to the filament::Engine associated with this BufferObject.
* @param buffer A BufferDescriptor that will hold the data copied back from GPU.
* @param byteOffset Offset in bytes into the BufferObject
*/
void getBuffer(Engine& engine, BufferDescriptor&& buffer, uint32_t byteOffset = 0);

/**
* Returns the size of this BufferObject in elements.
* @return The maximum capacity of the BufferObject.
Expand Down
9 changes: 9 additions & 0 deletions filament/include/filament/Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ class UTILS_PUBLIC Engine {
*/
uint32_t perFrameCommandsSizeMB = FILAMENT_PER_FRAME_COMMANDS_SIZE_IN_MB;
};

using Command = std::function<void()>;

/**
* Creates an instance of Engine
Expand Down Expand Up @@ -718,6 +720,13 @@ class UTILS_PUBLIC Engine {
*/
void execute();

/**
* Schedule a command to be run on the driver thread.
*
* @param command a command to be ran on the driver thread.
*/
void queueCommand(Command command);

/**
* Retrieves the job system that the Engine has ownership over.
*
Expand Down
Loading

0 comments on commit 136bb9b

Please sign in to comment.