Filament 源码阅读 - CommandStream到Driver的API调用过程

Filament Driver API 部分代码使用了宏来简化代码编写。 虽然代码看起来简洁了, 但是读代码和调试起来让人头疼。

从DriverAPI.inc 说起


filament 多个类包含了DriverAPI.inc, 目的是在这个类里面一次性实现一批API函数。以上图 NoopDriver 为例, 宏展开后代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
class NoopDriver {
NoopDriver() noexcept;
~NoopDriver() noexcept override;
Dispatcher getDispatcher() const noexcept final;

public:
static Driver* create();

private:

void tick(int dummy=0);
void beginFrame(int64_t monotonic_clock_ns, uint32_t frameId);
void setFrameScheduledCallback(backend::SwapChainHandle sch, backend::FrameScheduledCallback callback, void* user);
void setFrameCompletedCallback(backend::SwapChainHandle sch, backend::CallbackHandler* handler, backend::CallbackHandler::Callback callback, void* user);
void setPresentationTime(int64_t monotonic_clock_ns);
void endFrame(uint32_t frameId);
void flush(int dummy=0);
void finish(int dummy=0);
void resetState(int dummy=0);

backend::VertexBufferHandle createVertexBufferS() noexcept override { return backend::VertexBufferHandle((backend::VertexBufferHandle::HandleId)nextFakeHandle++); } void createVertexBufferR(backend::VertexBufferHandle, uint8_t bufferCount, uint8_t attributeCount, uint32_t vertexCount, backend::AttributeArray attributes) { }
backend::IndexBufferHandle createIndexBufferS() noexcept override { return backend::IndexBufferHandle((backend::IndexBufferHandle::HandleId)nextFakeHandle++); } void createIndexBufferR(backend::IndexBufferHandle, backend::ElementType elementType, uint32_t indexCount, backend::BufferUsage usage) { }
backend::BufferObjectHandle createBufferObjectS() noexcept override { return backend::BufferObjectHandle((backend::BufferObjectHandle::HandleId)nextFakeHandle++); } void createBufferObjectR(backend::BufferObjectHandle, uint32_t byteCount, backend::BufferObjectBinding bindingType, backend::BufferUsage usage) { }
backend::TextureHandle createTextureS() noexcept override { return backend::TextureHandle((backend::TextureHandle::HandleId)nextFakeHandle++); } void createTextureR(backend::TextureHandle, backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage) { }
backend::TextureHandle createTextureSwizzledS() noexcept override { return backend::TextureHandle((backend::TextureHandle::HandleId)nextFakeHandle++); } void createTextureSwizzledR(backend::TextureHandle, backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage, backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, backend::TextureSwizzle a) { }
backend::TextureHandle importTextureS() noexcept override { return backend::TextureHandle((backend::TextureHandle::HandleId)nextFakeHandle++); } void importTextureR(backend::TextureHandle, intptr_t id, backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage) { }
backend::SamplerGroupHandle createSamplerGroupS() noexcept override { return backend::SamplerGroupHandle((backend::SamplerGroupHandle::HandleId)nextFakeHandle++); } void createSamplerGroupR(backend::SamplerGroupHandle, uint32_t size, utils::FixedSizeString<32> debugName) { }
backend::RenderPrimitiveHandle createRenderPrimitiveS() noexcept override { return backend::RenderPrimitiveHandle((backend::RenderPrimitiveHandle::HandleId)nextFakeHandle++); } void createRenderPrimitiveR(backend::RenderPrimitiveHandle, backend::VertexBufferHandle vbh, backend::IndexBufferHandle ibh, backend::PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex, uint32_t count) { }
backend::ProgramHandle createProgramS() noexcept override { return backend::ProgramHandle((backend::ProgramHandle::HandleId)nextFakeHandle++); } void createProgramR(backend::ProgramHandle, backend::Program&& program) { }
backend::RenderTargetHandle createDefaultRenderTargetS() noexcept override { return backend::RenderTargetHandle((backend::RenderTargetHandle::HandleId)nextFakeHandle++); } void createDefaultRenderTargetR(backend::RenderTargetHandle, int dummy=0) { }
backend::RenderTargetHandle createRenderTargetS() noexcept override { return backend::RenderTargetHandle((backend::RenderTargetHandle::HandleId)nextFakeHandle++); } void createRenderTargetR(backend::RenderTargetHandle, backend::TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height, uint8_t samples, backend::MRT color, backend::TargetBufferInfo depth, backend::TargetBufferInfo stencil) { }
backend::FenceHandle createFenceS() noexcept override { return backend::FenceHandle((backend::FenceHandle::HandleId)nextFakeHandle++); } void createFenceR(backend::FenceHandle, int dummy=0) { }
backend::SwapChainHandle createSwapChainS() noexcept override { return backend::SwapChainHandle((backend::SwapChainHandle::HandleId)nextFakeHandle++); } void createSwapChainR(backend::SwapChainHandle, void* nativeWindow, uint64_t flags) { }
backend::SwapChainHandle createSwapChainHeadlessS() noexcept override { return backend::SwapChainHandle((backend::SwapChainHandle::HandleId)nextFakeHandle++); } void createSwapChainHeadlessR(backend::SwapChainHandle, uint32_t width, uint32_t height, uint64_t flags) { }
backend::TimerQueryHandle createTimerQueryS() noexcept override { return backend::TimerQueryHandle((backend::TimerQueryHandle::HandleId)nextFakeHandle++); } void createTimerQueryR(backend::TimerQueryHandle, int dummy=0) { }

void destroyVertexBuffer(backend::VertexBufferHandle vbh);
void destroyIndexBuffer(backend::IndexBufferHandle ibh);
void destroyBufferObject(backend::BufferObjectHandle ibh);
void destroyRenderPrimitive(backend::RenderPrimitiveHandle rph);
void destroyProgram(backend::ProgramHandle ph);
void destroySamplerGroup(backend::SamplerGroupHandle sbh);
void destroyTexture(backend::TextureHandle th);
void destroyRenderTarget(backend::RenderTargetHandle rth);
void destroySwapChain(backend::SwapChainHandle sch);
void destroyStream(backend::StreamHandle sh);
void destroyTimerQuery(backend::TimerQueryHandle sh);
void destroyFence(backend::FenceHandle fh);

void terminate() override;
backend::StreamHandle createStreamNative(void* stream) override;
backend::StreamHandle createStreamAcquired() override;
void setAcquiredImage(backend::StreamHandle stream, void* image, backend::CallbackHandler* handler, backend::StreamCallback cb, void* userData) override;
void setStreamDimensions(backend::StreamHandle stream, uint32_t width, uint32_t height) override;
int64_t getStreamTimestamp(backend::StreamHandle stream) override;
void updateStreams(backend::DriverApi* driver) override;
backend::FenceStatus getFenceStatus(backend::FenceHandle fh) override;
bool isTextureFormatSupported(backend::TextureFormat format) override;
bool isTextureSwizzleSupported() override;
bool isTextureFormatMipmappable(backend::TextureFormat format) override;
bool isRenderTargetFormatSupported(backend::TextureFormat format) override;
bool isFrameBufferFetchSupported() override;
bool isFrameBufferFetchMultiSampleSupported() override;
bool isFrameTimeSupported() override;
bool isAutoDepthResolveSupported() override;
bool isSRGBSwapChainSupported() override;
bool isStereoSupported() override;
bool isParallelShaderCompileSupported() override;
bool isDepthStencilResolveSupported() override;
uint8_t getMaxDrawBuffers() override;
size_t getMaxUniformBufferSize() override;
math::float2 getClipSpaceParams() override;
void setupExternalImage(void* image) override;
bool getTimerQueryValue(backend::TimerQueryHandle query, uint64_t* elapsedTime) override;
bool isWorkaroundNeeded(backend::Workaround workaround) override;
backend::FeatureLevel getFeatureLevel() override;
void setVertexBufferObject(backend::VertexBufferHandle vbh, uint32_t index, backend::BufferObjectHandle bufferObject);
void updateIndexBuffer(backend::IndexBufferHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset);
void updateBufferObject(backend::BufferObjectHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset);
void updateBufferObjectUnsynchronized(backend::BufferObjectHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset);
void resetBufferObject(backend::BufferObjectHandle ibh);
void updateSamplerGroup(backend::SamplerGroupHandle ubh, backend::BufferDescriptor&& data);
void setMinMaxLevels(backend::TextureHandle th, uint32_t minLevel, uint32_t maxLevel);
void update3DImage(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::PixelBufferDescriptor&& data);
void generateMipmaps(backend::TextureHandle th);
void setExternalImage(backend::TextureHandle th, void* image);
void setExternalImagePlane(backend::TextureHandle th, void* image, uint32_t plane);
void setExternalStream(backend::TextureHandle th, backend::StreamHandle sh);
void beginRenderPass(backend::RenderTargetHandle rth, const backend::RenderPassParams& params);
void endRenderPass(int dummy=0);
void nextSubpass(int dummy=0);
void beginTimerQuery(backend::TimerQueryHandle query);
void endTimerQuery(backend::TimerQueryHandle query);
void compilePrograms(backend::CompilerPriorityQueue priority, backend::CallbackHandler* handler, backend::CallbackHandler::Callback callback, void* user);
void makeCurrent(backend::SwapChainHandle schDraw, backend::SwapChainHandle schRead);
void commit(backend::SwapChainHandle sch);
void bindUniformBuffer(uint32_t index, backend::BufferObjectHandle ubh);
void bindBufferRange(BufferObjectBinding bindingType, uint32_t index, backend::BufferObjectHandle ubh, uint32_t offset, uint32_t size);
void unbindBuffer(BufferObjectBinding bindingType, uint32_t index);
void bindSamplers(uint32_t index, backend::SamplerGroupHandle sbh);
void insertEventMarker(const char* string, uint32_t len = 0);
void pushGroupMarker(const char* string, uint32_t len = 0);
void popGroupMarker(int dummy=0);
void startCapture(int dummy=0);
void stopCapture(int dummy=0);
void readPixels(backend::RenderTargetHandle src, uint32_t x, uint32_t y, uint32_t width, uint32_t height, backend::PixelBufferDescriptor&& data);
void readBufferSubData(backend::BufferObjectHandle src, uint32_t offset, uint32_t size, backend::BufferDescriptor&& data);
void blitDEPRECATED(backend::TargetBufferFlags buffers, backend::RenderTargetHandle dst, backend::Viewport dstRect, backend::RenderTargetHandle src, backend::Viewport srcRect, backend::SamplerMagFilter filter);
void resolve(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer);
void blit(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, math::uint2 dstOrigin, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer, math::uint2 srcOrigin, math::uint2 size);
void draw(backend::PipelineState state, backend::RenderPrimitiveHandle rph, uint32_t instanceCount);
void dispatchCompute(backend::ProgramHandle program, math::uint3 workGroupCount);
};

可以认为DriverAPI.inc 定义了一套需要实现的API接口。 OpenGLDriver 需要实现, VulkanDriver 也实现了一套。 而上层Engine使用CommandStream 来编码同一套API Command。

展开后代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
class CommandStream {
public:
void tick(int dummy=0) { DEBUG_COMMAND_BEGIN(tick, false, dummy); using Cmd = COMMAND_TYPE(tick); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.tick_, std::move(dummy)); DEBUG_COMMAND_END(tick, false); }
void beginFrame(int64_t monotonic_clock_ns, uint32_t frameId) { DEBUG_COMMAND_BEGIN(beginFrame, false, monotonic_clock_ns, frameId); using Cmd = COMMAND_TYPE(beginFrame); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.beginFrame_, std::move(monotonic_clock_ns), std::move(frameId)); DEBUG_COMMAND_END(beginFrame, false); }
void setFrameScheduledCallback(backend::SwapChainHandle sch, backend::FrameScheduledCallback callback, void* user) { DEBUG_COMMAND_BEGIN(setFrameScheduledCallback, false, sch, callback, user); using Cmd = COMMAND_TYPE(setFrameScheduledCallback); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setFrameScheduledCallback_, std::move(sch), std::move(callback), std::move(user)); DEBUG_COMMAND_END(setFrameScheduledCallback, false); }
void setFrameCompletedCallback(backend::SwapChainHandle sch, backend::CallbackHandler* handler, backend::CallbackHandler::Callback callback, void* user) { DEBUG_COMMAND_BEGIN(setFrameCompletedCallback, false, sch, handler, callback, user); using Cmd = COMMAND_TYPE(setFrameCompletedCallback); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setFrameCompletedCallback_, std::move(sch), std::move(handler), std::move(callback), std::move(user)); DEBUG_COMMAND_END(setFrameCompletedCallback, false); }
void setPresentationTime(int64_t monotonic_clock_ns) { DEBUG_COMMAND_BEGIN(setPresentationTime, false, monotonic_clock_ns); using Cmd = COMMAND_TYPE(setPresentationTime); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setPresentationTime_, std::move(monotonic_clock_ns)); DEBUG_COMMAND_END(setPresentationTime, false); }
void endFrame(uint32_t frameId) { DEBUG_COMMAND_BEGIN(endFrame, false, frameId); using Cmd = COMMAND_TYPE(endFrame); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.endFrame_, std::move(frameId)); DEBUG_COMMAND_END(endFrame, false); }
void flush(int dummy=0) { DEBUG_COMMAND_BEGIN(flush, false, dummy); using Cmd = COMMAND_TYPE(flush); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.flush_, std::move(dummy)); DEBUG_COMMAND_END(flush, false); }
void finish(int dummy=0) { DEBUG_COMMAND_BEGIN(finish, false, dummy); using Cmd = COMMAND_TYPE(finish); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.finish_, std::move(dummy)); DEBUG_COMMAND_END(finish, false); }
void resetState(int dummy=0) { DEBUG_COMMAND_BEGIN(resetState, false, dummy); using Cmd = COMMAND_TYPE(resetState); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.resetState_, std::move(dummy)); DEBUG_COMMAND_END(resetState, false); }
backend::VertexBufferHandle createVertexBuffer(uint8_t bufferCount, uint8_t attributeCount, uint32_t vertexCount, backend::AttributeArray attributes) { DEBUG_COMMAND_BEGIN(createVertexBuffer, false, bufferCount, attributeCount, vertexCount, attributes); backend::VertexBufferHandle result = mDriver.createVertexBufferS(); using Cmd = COMMAND_TYPE(createVertexBufferR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createVertexBuffer_, backend::VertexBufferHandle(result), std::move(bufferCount), std::move(attributeCount), std::move(vertexCount), std::move(attributes)); DEBUG_COMMAND_END(createVertexBuffer, false); return result; }
backend::IndexBufferHandle createIndexBuffer(backend::ElementType elementType, uint32_t indexCount, backend::BufferUsage usage) { DEBUG_COMMAND_BEGIN(createIndexBuffer, false, elementType, indexCount, usage); backend::IndexBufferHandle result = mDriver.createIndexBufferS(); using Cmd = COMMAND_TYPE(createIndexBufferR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createIndexBuffer_, backend::IndexBufferHandle(result), std::move(elementType), std::move(indexCount), std::move(usage)); DEBUG_COMMAND_END(createIndexBuffer, false); return result; }
backend::BufferObjectHandle createBufferObject(uint32_t byteCount, backend::BufferObjectBinding bindingType, backend::BufferUsage usage) { DEBUG_COMMAND_BEGIN(createBufferObject, false, byteCount, bindingType, usage); backend::BufferObjectHandle result = mDriver.createBufferObjectS(); using Cmd = COMMAND_TYPE(createBufferObjectR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createBufferObject_, backend::BufferObjectHandle(result), std::move(byteCount), std::move(bindingType), std::move(usage)); DEBUG_COMMAND_END(createBufferObject, false); return result; }
backend::TextureHandle createTexture(backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage) { DEBUG_COMMAND_BEGIN(createTexture, false, target, levels, format, samples, width, height, depth, usage); backend::TextureHandle result = mDriver.createTextureS(); using Cmd = COMMAND_TYPE(createTextureR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createTexture_, backend::TextureHandle(result), std::move(target), std::move(levels), std::move(format), std::move(samples), std::move(width), std::move(height), std::move(depth), std::move(usage)); DEBUG_COMMAND_END(createTexture, false); return result; }
backend::TextureHandle createTextureSwizzled(backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage, backend::TextureSwizzle r, backend::TextureSwizzle g, backend::TextureSwizzle b, backend::TextureSwizzle a) { DEBUG_COMMAND_BEGIN(createTextureSwizzled, false, target, levels, format, samples, width, height, depth, usage, r, g, b, a); backend::TextureHandle result = mDriver.createTextureSwizzledS(); using Cmd = COMMAND_TYPE(createTextureSwizzledR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createTextureSwizzled_, backend::TextureHandle(result), std::move(target), std::move(levels), std::move(format), std::move(samples), std::move(width), std::move(height), std::move(depth), std::move(usage), std::move(r), std::move(g), std::move(b), std::move(a)); DEBUG_COMMAND_END(createTextureSwizzled, false); return result; }
backend::TextureHandle importTexture(intptr_t id, backend::SamplerType target, uint8_t levels, backend::TextureFormat format, uint8_t samples, uint32_t width, uint32_t height, uint32_t depth, backend::TextureUsage usage) { DEBUG_COMMAND_BEGIN(importTexture, false, id, target, levels, format, samples, width, height, depth, usage); backend::TextureHandle result = mDriver.importTextureS(); using Cmd = COMMAND_TYPE(importTextureR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.importTexture_, backend::TextureHandle(result), std::move(id), std::move(target), std::move(levels), std::move(format), std::move(samples), std::move(width), std::move(height), std::move(depth), std::move(usage)); DEBUG_COMMAND_END(importTexture, false); return result; }
backend::SamplerGroupHandle createSamplerGroup(uint32_t size, utils::FixedSizeString<32> debugName) { DEBUG_COMMAND_BEGIN(createSamplerGroup, false, size, debugName); backend::SamplerGroupHandle result = mDriver.createSamplerGroupS(); using Cmd = COMMAND_TYPE(createSamplerGroupR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createSamplerGroup_, backend::SamplerGroupHandle(result), std::move(size), std::move(debugName)); DEBUG_COMMAND_END(createSamplerGroup, false); return result; }
backend::RenderPrimitiveHandle createRenderPrimitive(backend::VertexBufferHandle vbh, backend::IndexBufferHandle ibh, backend::PrimitiveType pt, uint32_t offset, uint32_t minIndex, uint32_t maxIndex, uint32_t count) { DEBUG_COMMAND_BEGIN(createRenderPrimitive, false, vbh, ibh, pt, offset, minIndex, maxIndex, count); backend::RenderPrimitiveHandle result = mDriver.createRenderPrimitiveS(); using Cmd = COMMAND_TYPE(createRenderPrimitiveR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createRenderPrimitive_, backend::RenderPrimitiveHandle(result), std::move(vbh), std::move(ibh), std::move(pt), std::move(offset), std::move(minIndex), std::move(maxIndex), std::move(count)); DEBUG_COMMAND_END(createRenderPrimitive, false); return result; }
backend::ProgramHandle createProgram(backend::Program&& program) { DEBUG_COMMAND_BEGIN(createProgram, false, program); backend::ProgramHandle result = mDriver.createProgramS(); using Cmd = COMMAND_TYPE(createProgramR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createProgram_, backend::ProgramHandle(result), std::move(program)); DEBUG_COMMAND_END(createProgram, false); return result; }
backend::RenderTargetHandle createDefaultRenderTarget(int dummy=0) { DEBUG_COMMAND_BEGIN(createDefaultRenderTarget, false, dummy); backend::RenderTargetHandle result = mDriver.createDefaultRenderTargetS(); using Cmd = COMMAND_TYPE(createDefaultRenderTargetR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createDefaultRenderTarget_, backend::RenderTargetHandle(result), std::move(dummy)); DEBUG_COMMAND_END(createDefaultRenderTarget, false); return result; }
backend::RenderTargetHandle createRenderTarget(backend::TargetBufferFlags targetBufferFlags, uint32_t width, uint32_t height, uint8_t samples, backend::MRT color, backend::TargetBufferInfo depth, backend::TargetBufferInfo stencil) { DEBUG_COMMAND_BEGIN(createRenderTarget, false, targetBufferFlags, width, height, samples, color, depth, stencil); backend::RenderTargetHandle result = mDriver.createRenderTargetS(); using Cmd = COMMAND_TYPE(createRenderTargetR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createRenderTarget_, backend::RenderTargetHandle(result), std::move(targetBufferFlags), std::move(width), std::move(height), std::move(samples), std::move(color), std::move(depth), std::move(stencil)); DEBUG_COMMAND_END(createRenderTarget, false); return result; }
backend::FenceHandle createFence(int dummy=0) { DEBUG_COMMAND_BEGIN(createFence, false, dummy); backend::FenceHandle result = mDriver.createFenceS(); using Cmd = COMMAND_TYPE(createFenceR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createFence_, backend::FenceHandle(result), std::move(dummy)); DEBUG_COMMAND_END(createFence, false); return result; }
backend::SwapChainHandle createSwapChain(void* nativeWindow, uint64_t flags) { DEBUG_COMMAND_BEGIN(createSwapChain, false, nativeWindow, flags); backend::SwapChainHandle result = mDriver.createSwapChainS(); using Cmd = COMMAND_TYPE(createSwapChainR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createSwapChain_, backend::SwapChainHandle(result), std::move(nativeWindow), std::move(flags)); DEBUG_COMMAND_END(createSwapChain, false); return result; }
backend::SwapChainHandle createSwapChainHeadless(uint32_t width, uint32_t height, uint64_t flags) { DEBUG_COMMAND_BEGIN(createSwapChainHeadless, false, width, height, flags); backend::SwapChainHandle result = mDriver.createSwapChainHeadlessS(); using Cmd = COMMAND_TYPE(createSwapChainHeadlessR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createSwapChainHeadless_, backend::SwapChainHandle(result), std::move(width), std::move(height), std::move(flags)); DEBUG_COMMAND_END(createSwapChainHeadless, false); return result; }
backend::TimerQueryHandle createTimerQuery(int dummy=0) { DEBUG_COMMAND_BEGIN(createTimerQuery, false, dummy); backend::TimerQueryHandle result = mDriver.createTimerQueryS(); using Cmd = COMMAND_TYPE(createTimerQueryR); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.createTimerQuery_, backend::TimerQueryHandle(result), std::move(dummy)); DEBUG_COMMAND_END(createTimerQuery, false); return result; }
void destroyVertexBuffer(backend::VertexBufferHandle vbh) { DEBUG_COMMAND_BEGIN(destroyVertexBuffer, false, vbh); using Cmd = COMMAND_TYPE(destroyVertexBuffer); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyVertexBuffer_, std::move(vbh)); DEBUG_COMMAND_END(destroyVertexBuffer, false); }
void destroyIndexBuffer(backend::IndexBufferHandle ibh) { DEBUG_COMMAND_BEGIN(destroyIndexBuffer, false, ibh); using Cmd = COMMAND_TYPE(destroyIndexBuffer); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyIndexBuffer_, std::move(ibh)); DEBUG_COMMAND_END(destroyIndexBuffer, false); }
void destroyBufferObject(backend::BufferObjectHandle ibh) { DEBUG_COMMAND_BEGIN(destroyBufferObject, false, ibh); using Cmd = COMMAND_TYPE(destroyBufferObject); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyBufferObject_, std::move(ibh)); DEBUG_COMMAND_END(destroyBufferObject, false); }
void destroyRenderPrimitive(backend::RenderPrimitiveHandle rph) { DEBUG_COMMAND_BEGIN(destroyRenderPrimitive, false, rph); using Cmd = COMMAND_TYPE(destroyRenderPrimitive); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyRenderPrimitive_, std::move(rph)); DEBUG_COMMAND_END(destroyRenderPrimitive, false); }
void destroyProgram(backend::ProgramHandle ph) { DEBUG_COMMAND_BEGIN(destroyProgram, false, ph); using Cmd = COMMAND_TYPE(destroyProgram); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyProgram_, std::move(ph)); DEBUG_COMMAND_END(destroyProgram, false); }
void destroySamplerGroup(backend::SamplerGroupHandle sbh) { DEBUG_COMMAND_BEGIN(destroySamplerGroup, false, sbh); using Cmd = COMMAND_TYPE(destroySamplerGroup); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroySamplerGroup_, std::move(sbh)); DEBUG_COMMAND_END(destroySamplerGroup, false); }
void destroyTexture(backend::TextureHandle th) { DEBUG_COMMAND_BEGIN(destroyTexture, false, th); using Cmd = COMMAND_TYPE(destroyTexture); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyTexture_, std::move(th)); DEBUG_COMMAND_END(destroyTexture, false); }
void destroyRenderTarget(backend::RenderTargetHandle rth) { DEBUG_COMMAND_BEGIN(destroyRenderTarget, false, rth); using Cmd = COMMAND_TYPE(destroyRenderTarget); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyRenderTarget_, std::move(rth)); DEBUG_COMMAND_END(destroyRenderTarget, false); }
void destroySwapChain(backend::SwapChainHandle sch) { DEBUG_COMMAND_BEGIN(destroySwapChain, false, sch); using Cmd = COMMAND_TYPE(destroySwapChain); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroySwapChain_, std::move(sch)); DEBUG_COMMAND_END(destroySwapChain, false); }
void destroyStream(backend::StreamHandle sh) { DEBUG_COMMAND_BEGIN(destroyStream, false, sh); using Cmd = COMMAND_TYPE(destroyStream); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyStream_, std::move(sh)); DEBUG_COMMAND_END(destroyStream, false); }
void destroyTimerQuery(backend::TimerQueryHandle sh) { DEBUG_COMMAND_BEGIN(destroyTimerQuery, false, sh); using Cmd = COMMAND_TYPE(destroyTimerQuery); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyTimerQuery_, std::move(sh)); DEBUG_COMMAND_END(destroyTimerQuery, false); }
void destroyFence(backend::FenceHandle fh) { DEBUG_COMMAND_BEGIN(destroyFence, false, fh); using Cmd = COMMAND_TYPE(destroyFence); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.destroyFence_, std::move(fh)); DEBUG_COMMAND_END(destroyFence, false); }
void terminate() { DEBUG_COMMAND_BEGIN(terminate, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(terminate, true); }); return apply(&Driver::terminate, mDriver, std::forward_as_tuple()); }
backend::StreamHandle createStreamNative(void* stream) { DEBUG_COMMAND_BEGIN(createStreamNative, true, stream); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(createStreamNative, true); }); return apply(&Driver::createStreamNative, mDriver, std::forward_as_tuple(stream)); }
backend::StreamHandle createStreamAcquired() { DEBUG_COMMAND_BEGIN(createStreamAcquired, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(createStreamAcquired, true); }); return apply(&Driver::createStreamAcquired, mDriver, std::forward_as_tuple()); }
void setAcquiredImage(backend::StreamHandle stream, void* image, backend::CallbackHandler* handler, backend::StreamCallback cb, void* userData) { DEBUG_COMMAND_BEGIN(setAcquiredImage, true, stream, image, handler, cb, userData); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(setAcquiredImage, true); }); return apply(&Driver::setAcquiredImage, mDriver, std::forward_as_tuple(stream, image, handler, cb, userData)); }
void setStreamDimensions(backend::StreamHandle stream, uint32_t width, uint32_t height) { DEBUG_COMMAND_BEGIN(setStreamDimensions, true, stream, width, height); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(setStreamDimensions, true); }); return apply(&Driver::setStreamDimensions, mDriver, std::forward_as_tuple(stream, width, height)); }
int64_t getStreamTimestamp(backend::StreamHandle stream) { DEBUG_COMMAND_BEGIN(getStreamTimestamp, true, stream); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getStreamTimestamp, true); }); return apply(&Driver::getStreamTimestamp, mDriver, std::forward_as_tuple(stream)); }
void updateStreams(backend::DriverApi* driver) { DEBUG_COMMAND_BEGIN(updateStreams, true, driver); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(updateStreams, true); }); return apply(&Driver::updateStreams, mDriver, std::forward_as_tuple(driver)); }
backend::FenceStatus getFenceStatus(backend::FenceHandle fh) { DEBUG_COMMAND_BEGIN(getFenceStatus, true, fh); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getFenceStatus, true); }); return apply(&Driver::getFenceStatus, mDriver, std::forward_as_tuple(fh)); }
bool isTextureFormatSupported(backend::TextureFormat format) { DEBUG_COMMAND_BEGIN(isTextureFormatSupported, true, format); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isTextureFormatSupported, true); }); return apply(&Driver::isTextureFormatSupported, mDriver, std::forward_as_tuple(format)); }
bool isTextureSwizzleSupported() { DEBUG_COMMAND_BEGIN(isTextureSwizzleSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isTextureSwizzleSupported, true); }); return apply(&Driver::isTextureSwizzleSupported, mDriver, std::forward_as_tuple()); }
bool isTextureFormatMipmappable(backend::TextureFormat format) { DEBUG_COMMAND_BEGIN(isTextureFormatMipmappable, true, format); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isTextureFormatMipmappable, true); }); return apply(&Driver::isTextureFormatMipmappable, mDriver, std::forward_as_tuple(format)); }
bool isRenderTargetFormatSupported(backend::TextureFormat format) { DEBUG_COMMAND_BEGIN(isRenderTargetFormatSupported, true, format); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isRenderTargetFormatSupported, true); }); return apply(&Driver::isRenderTargetFormatSupported, mDriver, std::forward_as_tuple(format)); }
bool isFrameBufferFetchSupported() { DEBUG_COMMAND_BEGIN(isFrameBufferFetchSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isFrameBufferFetchSupported, true); }); return apply(&Driver::isFrameBufferFetchSupported, mDriver, std::forward_as_tuple()); }
bool isFrameBufferFetchMultiSampleSupported() { DEBUG_COMMAND_BEGIN(isFrameBufferFetchMultiSampleSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isFrameBufferFetchMultiSampleSupported, true); }); return apply(&Driver::isFrameBufferFetchMultiSampleSupported, mDriver, std::forward_as_tuple()); }
bool isFrameTimeSupported() { DEBUG_COMMAND_BEGIN(isFrameTimeSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isFrameTimeSupported, true); }); return apply(&Driver::isFrameTimeSupported, mDriver, std::forward_as_tuple()); }
bool isAutoDepthResolveSupported() { DEBUG_COMMAND_BEGIN(isAutoDepthResolveSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isAutoDepthResolveSupported, true); }); return apply(&Driver::isAutoDepthResolveSupported, mDriver, std::forward_as_tuple()); }
bool isSRGBSwapChainSupported() { DEBUG_COMMAND_BEGIN(isSRGBSwapChainSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isSRGBSwapChainSupported, true); }); return apply(&Driver::isSRGBSwapChainSupported, mDriver, std::forward_as_tuple()); }
bool isStereoSupported() { DEBUG_COMMAND_BEGIN(isStereoSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isStereoSupported, true); }); return apply(&Driver::isStereoSupported, mDriver, std::forward_as_tuple()); }
bool isParallelShaderCompileSupported() { DEBUG_COMMAND_BEGIN(isParallelShaderCompileSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isParallelShaderCompileSupported, true); }); return apply(&Driver::isParallelShaderCompileSupported, mDriver, std::forward_as_tuple()); }
bool isDepthStencilResolveSupported() { DEBUG_COMMAND_BEGIN(isDepthStencilResolveSupported, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isDepthStencilResolveSupported, true); }); return apply(&Driver::isDepthStencilResolveSupported, mDriver, std::forward_as_tuple()); }
uint8_t getMaxDrawBuffers() { DEBUG_COMMAND_BEGIN(getMaxDrawBuffers, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getMaxDrawBuffers, true); }); return apply(&Driver::getMaxDrawBuffers, mDriver, std::forward_as_tuple()); }
size_t getMaxUniformBufferSize() { DEBUG_COMMAND_BEGIN(getMaxUniformBufferSize, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getMaxUniformBufferSize, true); }); return apply(&Driver::getMaxUniformBufferSize, mDriver, std::forward_as_tuple()); }
math::float2 getClipSpaceParams() { DEBUG_COMMAND_BEGIN(getClipSpaceParams, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getClipSpaceParams, true); }); return apply(&Driver::getClipSpaceParams, mDriver, std::forward_as_tuple()); }
void setupExternalImage(void* image) { DEBUG_COMMAND_BEGIN(setupExternalImage, true, image); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(setupExternalImage, true); }); return apply(&Driver::setupExternalImage, mDriver, std::forward_as_tuple(image)); }
bool getTimerQueryValue(backend::TimerQueryHandle query, uint64_t* elapsedTime) { DEBUG_COMMAND_BEGIN(getTimerQueryValue, true, query, elapsedTime); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getTimerQueryValue, true); }); return apply(&Driver::getTimerQueryValue, mDriver, std::forward_as_tuple(query, elapsedTime)); }
bool isWorkaroundNeeded(backend::Workaround workaround) { DEBUG_COMMAND_BEGIN(isWorkaroundNeeded, true, workaround); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(isWorkaroundNeeded, true); }); return apply(&Driver::isWorkaroundNeeded, mDriver, std::forward_as_tuple(workaround)); }
backend::FeatureLevel getFeatureLevel() { DEBUG_COMMAND_BEGIN(getFeatureLevel, true, ); AutoExecute callOnExit([=](){ DEBUG_COMMAND_END(getFeatureLevel, true); }); return apply(&Driver::getFeatureLevel, mDriver, std::forward_as_tuple()); }
void setVertexBufferObject(backend::VertexBufferHandle vbh, uint32_t index, backend::BufferObjectHandle bufferObject) { DEBUG_COMMAND_BEGIN(setVertexBufferObject, false, vbh, index, bufferObject); using Cmd = COMMAND_TYPE(setVertexBufferObject); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setVertexBufferObject_, std::move(vbh), std::move(index), std::move(bufferObject)); DEBUG_COMMAND_END(setVertexBufferObject, false); }
void updateIndexBuffer(backend::IndexBufferHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset) { DEBUG_COMMAND_BEGIN(updateIndexBuffer, false, ibh, data, byteOffset); using Cmd = COMMAND_TYPE(updateIndexBuffer); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.updateIndexBuffer_, std::move(ibh), std::move(data), std::move(byteOffset)); DEBUG_COMMAND_END(updateIndexBuffer, false); }
void updateBufferObject(backend::BufferObjectHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset) { DEBUG_COMMAND_BEGIN(updateBufferObject, false, ibh, data, byteOffset); using Cmd = COMMAND_TYPE(updateBufferObject); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.updateBufferObject_, std::move(ibh), std::move(data), std::move(byteOffset)); DEBUG_COMMAND_END(updateBufferObject, false); }
void updateBufferObjectUnsynchronized(backend::BufferObjectHandle ibh, backend::BufferDescriptor&& data, uint32_t byteOffset) { DEBUG_COMMAND_BEGIN(updateBufferObjectUnsynchronized, false, ibh, data, byteOffset); using Cmd = COMMAND_TYPE(updateBufferObjectUnsynchronized); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.updateBufferObjectUnsynchronized_, std::move(ibh), std::move(data), std::move(byteOffset)); DEBUG_COMMAND_END(updateBufferObjectUnsynchronized, false); }
void resetBufferObject(backend::BufferObjectHandle ibh) { DEBUG_COMMAND_BEGIN(resetBufferObject, false, ibh); using Cmd = COMMAND_TYPE(resetBufferObject); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.resetBufferObject_, std::move(ibh)); DEBUG_COMMAND_END(resetBufferObject, false); }
void updateSamplerGroup(backend::SamplerGroupHandle ubh, backend::BufferDescriptor&& data) { DEBUG_COMMAND_BEGIN(updateSamplerGroup, false, ubh, data); using Cmd = COMMAND_TYPE(updateSamplerGroup); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.updateSamplerGroup_, std::move(ubh), std::move(data)); DEBUG_COMMAND_END(updateSamplerGroup, false); }
void setMinMaxLevels(backend::TextureHandle th, uint32_t minLevel, uint32_t maxLevel) { DEBUG_COMMAND_BEGIN(setMinMaxLevels, false, th, minLevel, maxLevel); using Cmd = COMMAND_TYPE(setMinMaxLevels); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setMinMaxLevels_, std::move(th), std::move(minLevel), std::move(maxLevel)); DEBUG_COMMAND_END(setMinMaxLevels, false); }
void update3DImage(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::PixelBufferDescriptor&& data) { DEBUG_COMMAND_BEGIN(update3DImage, false, th, level, xoffset, yoffset, zoffset, width, height, depth, data); using Cmd = COMMAND_TYPE(update3DImage); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.update3DImage_, std::move(th), std::move(level), std::move(xoffset), std::move(yoffset), std::move(zoffset), std::move(width), std::move(height), std::move(depth), std::move(data)); DEBUG_COMMAND_END(update3DImage, false); }
void generateMipmaps(backend::TextureHandle th) { DEBUG_COMMAND_BEGIN(generateMipmaps, false, th); using Cmd = COMMAND_TYPE(generateMipmaps); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.generateMipmaps_, std::move(th)); DEBUG_COMMAND_END(generateMipmaps, false); }
void setExternalImage(backend::TextureHandle th, void* image) { DEBUG_COMMAND_BEGIN(setExternalImage, false, th, image); using Cmd = COMMAND_TYPE(setExternalImage); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setExternalImage_, std::move(th), std::move(image)); DEBUG_COMMAND_END(setExternalImage, false); }
void setExternalImagePlane(backend::TextureHandle th, void* image, uint32_t plane) { DEBUG_COMMAND_BEGIN(setExternalImagePlane, false, th, image, plane); using Cmd = COMMAND_TYPE(setExternalImagePlane); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setExternalImagePlane_, std::move(th), std::move(image), std::move(plane)); DEBUG_COMMAND_END(setExternalImagePlane, false); }
void setExternalStream(backend::TextureHandle th, backend::StreamHandle sh) { DEBUG_COMMAND_BEGIN(setExternalStream, false, th, sh); using Cmd = COMMAND_TYPE(setExternalStream); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.setExternalStream_, std::move(th), std::move(sh)); DEBUG_COMMAND_END(setExternalStream, false); }
void beginRenderPass(backend::RenderTargetHandle rth, const backend::RenderPassParams& params) { DEBUG_COMMAND_BEGIN(beginRenderPass, false, rth, params); using Cmd = COMMAND_TYPE(beginRenderPass); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.beginRenderPass_, std::move(rth), std::move(params)); DEBUG_COMMAND_END(beginRenderPass, false); }
void endRenderPass(int dummy=0) { DEBUG_COMMAND_BEGIN(endRenderPass, false, dummy); using Cmd = COMMAND_TYPE(endRenderPass); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.endRenderPass_, std::move(dummy)); DEBUG_COMMAND_END(endRenderPass, false); }
void nextSubpass(int dummy=0) { DEBUG_COMMAND_BEGIN(nextSubpass, false, dummy); using Cmd = COMMAND_TYPE(nextSubpass); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.nextSubpass_, std::move(dummy)); DEBUG_COMMAND_END(nextSubpass, false); }
void beginTimerQuery(backend::TimerQueryHandle query) { DEBUG_COMMAND_BEGIN(beginTimerQuery, false, query); using Cmd = COMMAND_TYPE(beginTimerQuery); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.beginTimerQuery_, std::move(query)); DEBUG_COMMAND_END(beginTimerQuery, false); }
void endTimerQuery(backend::TimerQueryHandle query) { DEBUG_COMMAND_BEGIN(endTimerQuery, false, query); using Cmd = COMMAND_TYPE(endTimerQuery); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.endTimerQuery_, std::move(query)); DEBUG_COMMAND_END(endTimerQuery, false); }
void compilePrograms(backend::CompilerPriorityQueue priority, backend::CallbackHandler* handler, backend::CallbackHandler::Callback callback, void* user) { DEBUG_COMMAND_BEGIN(compilePrograms, false, priority, handler, callback, user); using Cmd = COMMAND_TYPE(compilePrograms); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.compilePrograms_, std::move(priority), std::move(handler), std::move(callback), std::move(user)); DEBUG_COMMAND_END(compilePrograms, false); }
void makeCurrent(backend::SwapChainHandle schDraw, backend::SwapChainHandle schRead) { DEBUG_COMMAND_BEGIN(makeCurrent, false, schDraw, schRead); using Cmd = COMMAND_TYPE(makeCurrent); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.makeCurrent_, std::move(schDraw), std::move(schRead)); DEBUG_COMMAND_END(makeCurrent, false); }
void commit(backend::SwapChainHandle sch) { DEBUG_COMMAND_BEGIN(commit, false, sch); using Cmd = COMMAND_TYPE(commit); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.commit_, std::move(sch)); DEBUG_COMMAND_END(commit, false); }
void bindUniformBuffer(uint32_t index, backend::BufferObjectHandle ubh) { DEBUG_COMMAND_BEGIN(bindUniformBuffer, false, index, ubh); using Cmd = COMMAND_TYPE(bindUniformBuffer); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.bindUniformBuffer_, std::move(index), std::move(ubh)); DEBUG_COMMAND_END(bindUniformBuffer, false); }
void bindBufferRange(BufferObjectBinding bindingType, uint32_t index, backend::BufferObjectHandle ubh, uint32_t offset, uint32_t size) { DEBUG_COMMAND_BEGIN(bindBufferRange, false, bindingType, index, ubh, offset, size); using Cmd = COMMAND_TYPE(bindBufferRange); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.bindBufferRange_, std::move(bindingType), std::move(index), std::move(ubh), std::move(offset), std::move(size)); DEBUG_COMMAND_END(bindBufferRange, false); }
void unbindBuffer(BufferObjectBinding bindingType, uint32_t index) { DEBUG_COMMAND_BEGIN(unbindBuffer, false, bindingType, index); using Cmd = COMMAND_TYPE(unbindBuffer); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.unbindBuffer_, std::move(bindingType), std::move(index)); DEBUG_COMMAND_END(unbindBuffer, false); }
void bindSamplers(uint32_t index, backend::SamplerGroupHandle sbh) { DEBUG_COMMAND_BEGIN(bindSamplers, false, index, sbh); using Cmd = COMMAND_TYPE(bindSamplers); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.bindSamplers_, std::move(index), std::move(sbh)); DEBUG_COMMAND_END(bindSamplers, false); }
void insertEventMarker(const char* string, uint32_t len = 0) { DEBUG_COMMAND_BEGIN(insertEventMarker, false, string, len = 0); using Cmd = COMMAND_TYPE(insertEventMarker); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.insertEventMarker_, std::move(string), std::move(len = 0)); DEBUG_COMMAND_END(insertEventMarker, false); }
void pushGroupMarker(const char* string, uint32_t len = 0) { DEBUG_COMMAND_BEGIN(pushGroupMarker, false, string, len = 0); using Cmd = COMMAND_TYPE(pushGroupMarker); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.pushGroupMarker_, std::move(string), std::move(len = 0)); DEBUG_COMMAND_END(pushGroupMarker, false); }
void popGroupMarker(int dummy=0) { DEBUG_COMMAND_BEGIN(popGroupMarker, false, dummy); using Cmd = COMMAND_TYPE(popGroupMarker); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.popGroupMarker_, std::move(dummy)); DEBUG_COMMAND_END(popGroupMarker, false); }
void startCapture(int dummy=0) { DEBUG_COMMAND_BEGIN(startCapture, false, dummy); using Cmd = COMMAND_TYPE(startCapture); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.startCapture_, std::move(dummy)); DEBUG_COMMAND_END(startCapture, false); }
void stopCapture(int dummy=0) { DEBUG_COMMAND_BEGIN(stopCapture, false, dummy); using Cmd = COMMAND_TYPE(stopCapture); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.stopCapture_, std::move(dummy)); DEBUG_COMMAND_END(stopCapture, false); }
void readPixels(backend::RenderTargetHandle src, uint32_t x, uint32_t y, uint32_t width, uint32_t height, backend::PixelBufferDescriptor&& data) { DEBUG_COMMAND_BEGIN(readPixels, false, src, x, y, width, height, data); using Cmd = COMMAND_TYPE(readPixels); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.readPixels_, std::move(src), std::move(x), std::move(y), std::move(width), std::move(height), std::move(data)); DEBUG_COMMAND_END(readPixels, false); }
void readBufferSubData(backend::BufferObjectHandle src, uint32_t offset, uint32_t size, backend::BufferDescriptor&& data) { DEBUG_COMMAND_BEGIN(readBufferSubData, false, src, offset, size, data); using Cmd = COMMAND_TYPE(readBufferSubData); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.readBufferSubData_, std::move(src), std::move(offset), std::move(size), std::move(data)); DEBUG_COMMAND_END(readBufferSubData, false); }
void blitDEPRECATED(backend::TargetBufferFlags buffers, backend::RenderTargetHandle dst, backend::Viewport dstRect, backend::RenderTargetHandle src, backend::Viewport srcRect, backend::SamplerMagFilter filter) { DEBUG_COMMAND_BEGIN(blitDEPRECATED, false, buffers, dst, dstRect, src, srcRect, filter); using Cmd = COMMAND_TYPE(blitDEPRECATED); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.blitDEPRECATED_, std::move(buffers), std::move(dst), std::move(dstRect), std::move(src), std::move(srcRect), std::move(filter)); DEBUG_COMMAND_END(blitDEPRECATED, false); }
void resolve(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer) { DEBUG_COMMAND_BEGIN(resolve, false, dst, dstLevel, dstLayer, src, srcLevel, srcLayer); using Cmd = COMMAND_TYPE(resolve); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.resolve_, std::move(dst), std::move(dstLevel), std::move(dstLayer), std::move(src), std::move(srcLevel), std::move(srcLayer)); DEBUG_COMMAND_END(resolve, false); }
void blit(backend::TextureHandle dst, uint8_t dstLevel, uint8_t dstLayer, math::uint2 dstOrigin, backend::TextureHandle src, uint8_t srcLevel, uint8_t srcLayer, math::uint2 srcOrigin, math::uint2 size) { DEBUG_COMMAND_BEGIN(blit, false, dst, dstLevel, dstLayer, dstOrigin, src, srcLevel, srcLayer, srcOrigin, size); using Cmd = COMMAND_TYPE(blit); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.blit_, std::move(dst), std::move(dstLevel), std::move(dstLayer), std::move(dstOrigin), std::move(src), std::move(srcLevel), std::move(srcLayer), std::move(srcOrigin), std::move(size)); DEBUG_COMMAND_END(blit, false); }
void draw(backend::PipelineState state, backend::RenderPrimitiveHandle rph, uint32_t instanceCount) { DEBUG_COMMAND_BEGIN(draw, false, state, rph, instanceCount); using Cmd = COMMAND_TYPE(draw); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.draw_, std::move(state), std::move(rph), std::move(instanceCount)); DEBUG_COMMAND_END(draw, false); }
void dispatchCompute(backend::ProgramHandle program, math::uint3 workGroupCount) { DEBUG_COMMAND_BEGIN(dispatchCompute, false, program, workGroupCount); using Cmd = COMMAND_TYPE(dispatchCompute); void* const p = allocateCommand(CommandBase::align(sizeof(Cmd))); new(p) Cmd(mDispatcher.dispatchCompute_, std::move(program), std::move(workGroupCount)); DEBUG_COMMAND_END(dispatchCompute, false); }
};

API命令编码到API执行

Engine 通过 CommandStream调用一个API时, 将一个命令放置在命令队列中。 而Engine loop负责消费这个命令队列, 当队列flush(), 取一批命令执行。

CommandStream 的命令编码

举个例子, CommandStream创建顶点缓冲:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CommandStream {
// ...
backend::VertexBufferHandle createVertexBuffer(
uint8_t bufferCount,
uint8_t attributeCount,
uint32_t vertexCount,
backend::AttributeArray attributes)
{
DEBUG_COMMAND_BEGIN(createVertexBuffer, false, bufferCount, attributeCount, vertexCount, attributes);
backend::VertexBufferHandle result = mDriver.createVertexBufferS();
using Cmd = COMMAND_TYPE(createVertexBufferR);
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd)));
new(p) Cmd(mDispatcher.createVertexBuffer_, backend::VertexBufferHandle(result), std::move(bufferCount), std::move(attributeCount), std::move(vertexCount), std::move(attributes));
DEBUG_COMMAND_END(createVertexBuffer, false);
return result;
}
}
  1. 调用到 mDriver.createVertexBufferS() ,产生一个VertexBufferHandle
  2. 在命令RingBuffer 里分配一个createVertexBufferR的Cmd槽位
  3. 在刚刚分配的Cmd槽位 原地构造Cmd
  4. 返回VertexBufferHandle

Handle 机制

这里需要先说下Driver 资源的Handle机制

1
2
3
4
5
6
7
8
9
10
class HandleBase {
using HandleId = uint32_t;
HandleId object;
}

template<typename T>
struct Handle : public HandleBase {
}

using VertexBufferHandle = Handle<HwVertexBuffer>;

整理一下Handle 的代码, 它只是一个HwVertexBuffer的安全封装, 用一个uint32来指示内部资源. Driver 自己来管理Handle, 以OpenGLDriver 为例:

1
2
3
4
// initHandle来生成一个Handle, Handle是在handle pool里分配的, HandleAllocator记录了Handle 与HwVertexBuffer* 的对应关系
Handle<HwVertexBuffer> OpenGLDriver::createVertexBufferS() noexcept {
return initHandle<GLVertexBuffer>();
}

也就是说, 执行完createXXXS() 系列函数后。 Driver负责在HandlePool 里面分配一个HwXXX资源, 并且用一个uint32的句柄可以快速查到这个资源。 句柄映射逻辑可以从handle_cast<>() 看起

Cmd的构造

把一个API 封装成一个命令, 暂时把这个封装好的命令称为Cmd。 Cmd类代码如下:

1
2
3
4
using Cmd = COMMAND_TYPE(createVertexBufferR);

// 展开后变成
using Cmd = CommandType<decltype(&Driver::createVertexBufferR)>::Command<&Driver::createVertexBufferR>;

现在Cmd其实就是一个特化了 Driver::XXX 成员函数(作为模板参数) 的Command模板类。 一切Cmd 都继承自CommandBase。构造一个Cmd的代码如下:

1
2
3
4
5
6
7
8
9
10
11
// class CommandStream {
// ...
// backend::VertexBufferHandle createVertexBuffer(
void* const p = allocateCommand(CommandBase::align(sizeof(Cmd)));
new(p) Cmd(mDispatcher.createVertexBuffer_,
backend::VertexBufferHandle(result),
std::move(bufferCount),
std::move(attributeCount),
std::move(vertexCount),
std::move(attributes));
// ...

就地构造的时候, 第一个参数mDispatcher.createVertexBuffer_ 是一个函数指针。 接着是Handle, 然后是资源所需的参数
嗯, 带下划线这个函数是哪来的呢,继续往下看。

Dispatcher

1
2
3
4
5
6
7
8
9
10
// Dispatcher.h
class Dispatcher {
public:
using Execute = void (*)(Driver& driver, CommandBase* self, intptr_t* next);
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) Execute methodName##_;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) Execute methodName##_;

#include "DriverAPI.inc"
};

又是包含了DriverAPI.inc。 对于createVertexBuffer, 有一条函数指针记录 Execute createVertexBuffer_。 而API系列函数指针是ConcreteDispatcher在最开始make()填充的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
template<typename ConcreteDriver>
class ConcreteDispatcher {
public:

static Dispatcher make() noexcept;

private:
#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
static void methodName(Driver& driver, CommandBase* base, intptr_t* next) { \
SYSTRACE() \
using Cmd = COMMAND_TYPE(methodName); \
ConcreteDriver& concreteDriver = static_cast<ConcreteDriver&>(driver); \
Cmd::execute(&ConcreteDriver::methodName, concreteDriver, base, next); \
}
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
static void methodName(Driver& driver, CommandBase* base, intptr_t* next) { \
SYSTRACE() \
using Cmd = COMMAND_TYPE(methodName##R); \
ConcreteDriver& concreteDriver = static_cast<ConcreteDriver&>(driver); \
Cmd::execute(&ConcreteDriver::methodName##R, concreteDriver, base, next); \
}
#include "private/backend/DriverAPI.inc"
};

template<typename ConcreteDriver>
UTILS_NOINLINE
Dispatcher ConcreteDispatcher<ConcreteDriver>::make() noexcept {
Dispatcher dispatcher;

#define DECL_DRIVER_API_SYNCHRONOUS(RetType, methodName, paramsDecl, params)
#define DECL_DRIVER_API(methodName, paramsDecl, params) \
dispatcher.methodName##_ = &ConcreteDispatcher::methodName;
#define DECL_DRIVER_API_RETURN(RetType, methodName, paramsDecl, params) \
dispatcher.methodName##_ = &ConcreteDispatcher::methodName;

#include "private/backend/DriverAPI.inc"

return dispatcher;
}

展开看一下, 注意里面的Cmd::execute 静态函数调用。 只要你去调用dispatcher的函数指针,最后就会执行到静态函数Cmd::execute。而Cmd::execute 马上就会执行 OpenGLDriver::createVertexBufferR。 当然现在还没有到真正执行的时机, 只是把dispatcher的函数指针作为Cmd构造的第一个参数传进去保存了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 这里ConcreteDriver 根据使用的backend来实例化, 比如用OpenGL, 这里就是OpenGLDriver
template<typename ConcreteDriver>
class ConcreteDispatcher {
// ... 其他的API
static void createVertexBuffer(Driver& driver, CommandBase* base, intptr_t* next) {
using Cmd = COMMAND_TYPE(createVertexBufferR);
ConcreteDriver& concreteDriver = static_cast<ConcreteDriver&>(driver);
Cmd::execute(&ConcreteDriver::createVertexBufferR, concreteDriver, base, next);
}
};

template<typename ConcreteDriver>
Dispatcher ConcreteDispatcher<ConcreteDriver>::make() noexcept {
Dispatcher dispatcher;
// ... 其他的API初始化
dispatcher.createVertexBuffer_ = &ConcreteDispatcher::createVertexBuffer;
}

CommandBuffer 的命令执行

现在说回Cmd 环形队列CommandBufferQueue。 CommandStream 里面用一个CircularBuffer 来分配Cmd(大小8, 对齐8)。 每次调用CommandStream 上的API时, 就在这个队列里面分配一个Cmd。而这个队列的消费就比较简单了, EngineLoop 里面一直在CommandBufferQueue上等待可执行的Cmd, 拿到一批消费(执行)一批。 消费的CallStack如下:

总结

filament 使用一个DriverAPI.inc 文件批量定义了一套图形API。CommandStream 和具体Driver通过包含这个头文件来实现一套API的调用机制。 前台Engine调用CommandStream里的API来编码Cmd到一个命令队列中, 而在Engine Loop 里面循环消费Cmd(就是调用里面的函数指针), 最终直行到具体Driver的API。