Make buffer binding more Vulkan/Metal-like

This commit is contained in:
Henrik Rydgård 2017-01-17 23:14:47 +07:00
parent 58ecda4e4b
commit d8dbb8389b
7 changed files with 114 additions and 64 deletions

View file

@ -250,7 +250,9 @@ void SoftGPU::CopyToCurrentFboFromDisplayRam(int srcwidth, int srcheight) {
texColor->SetMatrix4x4("WorldViewProj", identity4x4);
thin3d->BindPipeline(texColor);
thin3d->DrawIndexed(vdata, idata, 6, 0);
thin3d->BindVertexBuffers(0, 1, &vdata, nullptr);
thin3d->BindIndexBuffer(idata, 0);
thin3d->DrawIndexed(6, 0);
}
void SoftGPU::CopyDisplayToOutput()

View file

@ -94,8 +94,9 @@ void DrawBuffer::Flush(bool set_blend_state) {
t3d_->BindPipeline(pipeline_);
if (vbuf_) {
vbuf_->SubData((const uint8_t *)verts_, 0, sizeof(Vertex) * count_);
t3d_->BindVertexBuffers(0, 1, &vbuf_, nullptr);
int offset = 0;
t3d_->Draw(vbuf_, count_, offset);
t3d_->Draw(count_, offset);
} else {
t3d_->DrawUP((const void *)verts_, count_);
}

View file

@ -510,6 +510,9 @@ public:
virtual void BindSamplerStates(int start, int count, SamplerState **state) = 0;
virtual void BindTextures(int start, int count, Texture **textures) = 0;
virtual void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) = 0;
virtual void BindIndexBuffer(Buffer *indexBuffer, int offset) = 0;
void BindTexture(int stage, Texture *texture) {
BindTextures(stage, 1, &texture);
} // from sampler 0 and upwards
@ -517,8 +520,8 @@ public:
virtual void BindPipeline(Pipeline *pipeline) = 0;
// TODO: Add more sophisticated draws with buffer offsets, and multidraws.
virtual void Draw(Buffer *vdata, int vertexCount, int offset) = 0;
virtual void DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) = 0;
virtual void Draw(int vertexCount, int offset) = 0;
virtual void DrawIndexed(int vertexCount, int offset) = 0;
virtual void DrawUP(const void *vdata, int vertexCount) = 0;
// Render pass management. Default implementations here.

View file

@ -42,6 +42,8 @@ public:
void BindTextures(int start, int count, Texture **textures) override;
void BindSamplerStates(int start, int count, SamplerState **states) override;
void BindPipeline(Pipeline *pipeline) override;
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override;
void BindIndexBuffer(Buffer *indexBuffer, int offset) override;
// Raster state
void SetScissorRect(int left, int top, int width, int height) override;
@ -50,8 +52,8 @@ public:
memcpy(blendFactor_, color, sizeof(float) * 4);
}
void Draw(Buffer *vdata, int vertexCount, int offset) override;
void DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal);
@ -458,11 +460,16 @@ Buffer *D3D11DrawContext::CreateBuffer(size_t size, uint32_t usageFlags) {
return b;
}
void D3D11DrawContext::Draw(Buffer *vdata, int vertexCount, int offset) {
void D3D11DrawContext::BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) {
}
void D3D11DrawContext::BindIndexBuffer(Buffer *indexBuffer, int offset) {
}
void D3D11DrawContext::Draw(int vertexCount, int offset) {
ApplyCurrentState();
}
void D3D11DrawContext::DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) {
void D3D11DrawContext::DrawIndexed(int vertexCount, int offset) {
ApplyCurrentState();
}

View file

@ -193,18 +193,20 @@ public:
}
};
class Thin3DDX9Buffer : public Buffer {
// Simulate a simple buffer type like the other backends have, use the usage flags to create the right internal type.
class D3D9Buffer : public Buffer {
public:
Thin3DDX9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) {
D3D9Buffer(LPDIRECT3DDEVICE9 device, size_t size, uint32_t flags) : vbuffer_(nullptr), ibuffer_(nullptr), maxSize_(size) {
if (flags & BufferUsageFlag::INDEXDATA) {
DWORD usage = D3DUSAGE_DYNAMIC;
device->CreateIndexBuffer((UINT)size, usage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &ibuffer_, NULL);
} else {
}
else {
DWORD usage = D3DUSAGE_DYNAMIC;
device->CreateVertexBuffer((UINT)size, usage, 0, D3DPOOL_DEFAULT, &vbuffer_, NULL);
}
}
virtual ~Thin3DDX9Buffer() override {
virtual ~D3D9Buffer() override {
if (ibuffer_) {
ibuffer_->Release();
}
@ -255,22 +257,13 @@ public:
}
}
}
void BindAsVertexBuf(LPDIRECT3DDEVICE9 device, int vertexSize, int offset = 0) {
if (vbuffer_)
device->SetStreamSource(0, vbuffer_, offset, vertexSize);
}
void BindAsIndexBuf(LPDIRECT3DDEVICE9 device) {
if (ibuffer_)
device->SetIndices(ibuffer_);
}
private:
public:
LPDIRECT3DVERTEXBUFFER9 vbuffer_;
LPDIRECT3DINDEXBUFFER9 ibuffer_;
size_t maxSize_;
};
class D3D9InputLayout : public InputLayout {
public:
D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc &desc);
@ -533,7 +526,18 @@ public:
s->Apply(device_, start + i);
}
}
void BindPipeline(Pipeline *pipeline) {
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override {
for (int i = 0; i < count; i++) {
curVBuffers_[i + start] = (D3D9Buffer *)buffers[i];
curVBufferOffsets_[i + start] = offsets ? offsets[i] : 0;
}
}
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
curIBuffer_ = (D3D9Buffer *)indexBuffer;
curIBufferOffset_ = offset;
}
void BindPipeline(Pipeline *pipeline) override {
curPipeline_ = (D3D9Pipeline *)pipeline;
}
@ -542,8 +546,8 @@ public:
void SetViewports(int count, Viewport *viewports) override;
void SetBlendFactor(float color[4]) override;
void Draw(Buffer *vdata, int vertexCount, int offset) override;
void DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal);
@ -568,8 +572,14 @@ private:
D3DADAPTER_IDENTIFIER9 identifier_;
D3DCAPS9 d3dCaps_;
char shadeLangVersion_[64];
D3D9Pipeline *curPipeline_;
DeviceCaps caps_;
// Bound state
D3D9Pipeline *curPipeline_;
D3D9Buffer *curVBuffers_[4];
int curVBufferOffsets_[4];
D3D9Buffer *curIBuffer_;
int curIBufferOffset_;
};
D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, IDirect3DDevice9 *device, IDirect3DDevice9Ex *deviceEx)
@ -768,7 +778,7 @@ D3D9InputLayout::D3D9InputLayout(LPDIRECT3DDEVICE9 device, const InputLayoutDesc
}
Buffer *D3D9Context::CreateBuffer(size_t size, uint32_t usageFlags) {
return new Thin3DDX9Buffer(device_, size, usageFlags);
return new D3D9Buffer(device_, size, usageFlags);
}
void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device) {
@ -779,23 +789,21 @@ void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device) {
raster->Apply(device);
}
void D3D9Context::Draw(Buffer *vdata, int vertexCount, int offset) {
Thin3DDX9Buffer *vbuf = static_cast<Thin3DDX9Buffer *>(vdata);
vbuf->BindAsVertexBuf(device_, curPipeline_->inputLayout->GetStride(0), offset);
void D3D9Context::Draw(int vertexCount, int offset) {
device_->SetStreamSource(0, curVBuffers_[0]->vbuffer_, curVBufferOffsets_[0], curPipeline_->inputLayout->GetStride(0));
curPipeline_->Apply(device_);
curPipeline_->inputLayout->Apply(device_);
device_->DrawPrimitive(curPipeline_->prim, offset, vertexCount / 3);
}
void D3D9Context::DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) {
Thin3DDX9Buffer *vbuf = static_cast<Thin3DDX9Buffer *>(vdata);
Thin3DDX9Buffer *ibuf = static_cast<Thin3DDX9Buffer *>(idata);
void D3D9Context::DrawIndexed(int vertexCount, int offset) {
D3D9Buffer *vbuf = static_cast<D3D9Buffer *>(curVBuffers_[0]);
D3D9Buffer *ibuf = static_cast<D3D9Buffer *>(curIBuffer_);
curPipeline_->Apply(device_);
curPipeline_->inputLayout->Apply(device_);
vbuf->BindAsVertexBuf(device_, curPipeline_->inputLayout->GetStride(0), offset);
ibuf->BindAsIndexBuf(device_);
device_->SetStreamSource(0, curVBuffers_[0]->vbuffer_, curVBufferOffsets_[0], curPipeline_->inputLayout->GetStride(0));
device_->SetIndices(curIBuffer_->ibuffer_);
device_->DrawIndexedPrimitive(curPipeline_->prim, 0, 0, vertexCount, 0, vertexCount / curPipeline_->primDivisor);
}

View file

@ -284,13 +284,13 @@ public:
}
void SetData(const uint8_t *data, size_t size) override {
Bind();
Bind(0);
glBufferData(target_, size, data, usage_);
knownSize_ = size;
}
void SubData(const uint8_t *data, size_t offset, size_t size) override {
Bind();
Bind(0);
if (size + offset > knownSize_) {
// Allocate the buffer.
glBufferData(target_, size + offset, NULL, usage_);
@ -298,7 +298,8 @@ public:
}
glBufferSubData(target_, offset, size, data);
}
void Bind() {
void Bind(int offset) {
// TODO: Can't support offset using ES 2.0
glBindBuffer(target_, buffer_);
}
@ -555,11 +556,22 @@ public:
void BindTextures(int start, int count, Texture **textures) override;
void BindPipeline(Pipeline *pipeline) override;
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override {
for (int i = 0; i < count; i++) {
curVBuffers_[i + start] = (OpenGLBuffer *)buffers[i];
curVBufferOffsets_[i + start] = offsets ? offsets[i] : 0;
}
}
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
curIBuffer_ = (OpenGLBuffer *)indexBuffer;
curIBufferOffset_ = offset;
}
// TODO: Add more sophisticated draws.
void Draw(Buffer *vdata, int vertexCount, int offset) override;
void DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
std::string GetInfoString(InfoField info) const override {
@ -594,8 +606,14 @@ public:
}
std::vector<OpenGLSamplerState *> samplerStates_;
OpenGLPipeline *curPipeline_;
DeviceCaps caps_;
// Bound state
OpenGLPipeline *curPipeline_;
OpenGLBuffer *curVBuffers_[4];
int curVBufferOffsets_[4];
OpenGLBuffer *curIBuffer_;
int curIBufferOffset_;
};
OpenGLContext::OpenGLContext() {
@ -1008,10 +1026,8 @@ void OpenGLContext::BindPipeline(Pipeline *pipeline) {
curPipeline_->raster->Apply();
}
void OpenGLContext::Draw(Buffer *vdata, int vertexCount, int offset) {
OpenGLBuffer *vbuf = static_cast<OpenGLBuffer *>(vdata);
vbuf->Bind();
void OpenGLContext::Draw(int vertexCount, int offset) {
curVBuffers_[0]->Bind(curVBufferOffsets_[0]);
curPipeline_->inputLayout->Apply();
curPipeline_->Apply();
@ -1021,15 +1037,12 @@ void OpenGLContext::Draw(Buffer *vdata, int vertexCount, int offset) {
curPipeline_->inputLayout->Unapply();
}
void OpenGLContext::DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) {
OpenGLBuffer *vbuf = static_cast<OpenGLBuffer *>(vdata);
OpenGLBuffer *ibuf = static_cast<OpenGLBuffer *>(idata);
vbuf->Bind();
void OpenGLContext::DrawIndexed(int vertexCount, int offset) {
curVBuffers_[0]->Bind(curVBufferOffsets_[0]);
curPipeline_->inputLayout->Apply();
curPipeline_->Apply();
// Note: ibuf binding is stored in the VAO, so call this after binding the fmt.
ibuf->Bind();
curIBuffer_->Bind(curIBufferOffset_);
glDrawElements(curPipeline_->prim, vertexCount, GL_UNSIGNED_INT, (const void *)(size_t)offset);

View file

@ -177,12 +177,12 @@ public:
// Very simplistic buffer that will simply copy its contents into our "pushbuffer" when it's time to draw,
// to avoid synchronization issues.
class Thin3DVKBuffer : public Buffer {
class VKBuffer : public Buffer {
public:
Thin3DVKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
VKBuffer(size_t size, uint32_t flags) : dataSize_(size) {
data_ = new uint8_t[size];
}
~Thin3DVKBuffer() override {
~VKBuffer() override {
delete[] data_;
}
@ -202,7 +202,7 @@ public:
size_t GetSize() const { return dataSize_; }
const uint8_t *GetData() const { return data_; }
private:
private:
uint8_t *data_;
size_t dataSize_;
};
@ -376,9 +376,21 @@ public:
curPipeline_ = (VKPipeline *)pipeline;
}
// TODO: Make VKBuffers proper buffers, and do a proper binding model. This is just silly.
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override {
for (int i = 0; i < count; i++) {
curVBuffers_[i + start] = (VKBuffer *)buffers[i];
curVBufferOffsets_[i + start] = offsets ? offsets[i] : 0;
}
}
void BindIndexBuffer(Buffer *indexBuffer, int offset) override {
curIBuffer_ = (VKBuffer *)indexBuffer;
curIBufferOffset_ = offset;
}
// TODO: Add more sophisticated draws.
void Draw(Buffer *vdata, int vertexCount, int offset) override;
void DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
@ -414,6 +426,10 @@ private:
VulkanContext *vulkan_;
VKPipeline *curPipeline_;
VKBuffer *curVBuffers_[4];
int curVBufferOffsets_[4];
VKBuffer *curIBuffer_;
int curIBufferOffset_;
VkDescriptorSetLayout descriptorSetLayout_;
VkPipelineLayout pipelineLayout_;
@ -1001,7 +1017,7 @@ BlendState *VKContext::CreateBlendState(const BlendStateDesc &desc) {
}
Buffer *VKContext::CreateBuffer(size_t size, uint32_t usageFlags) {
return new Thin3DVKBuffer(size, usageFlags);
return new VKBuffer(size, usageFlags);
}
void VKContext::BindTextures(int start, int count, Texture **textures) {
@ -1061,10 +1077,10 @@ inline VkPrimitiveTopology PrimToVK(Primitive prim) {
}
}
void VKContext::Draw(Buffer *vdata, int vertexCount, int offset) {
void VKContext::Draw(int vertexCount, int offset) {
ApplyDynamicState();
Thin3DVKBuffer *vbuf = static_cast<Thin3DVKBuffer *>(vdata);
VKBuffer *vbuf = curVBuffers_[0];
VkBuffer vulkanVbuf;
VkBuffer vulkanUBObuf;
@ -1080,11 +1096,11 @@ void VKContext::Draw(Buffer *vdata, int vertexCount, int offset) {
vkCmdDraw(cmd_, vertexCount, 1, offset, 0);
}
void VKContext::DrawIndexed(Buffer *vdata, Buffer *idata, int vertexCount, int offset) {
void VKContext::DrawIndexed(int vertexCount, int offset) {
ApplyDynamicState();
Thin3DVKBuffer *ibuf = static_cast<Thin3DVKBuffer *>(idata);
Thin3DVKBuffer *vbuf = static_cast<Thin3DVKBuffer *>(vdata);
VKBuffer *ibuf = static_cast<VKBuffer *>(curIBuffer_);
VKBuffer *vbuf = static_cast<VKBuffer *>(curVBuffers_[0]);
VkBuffer vulkanVbuf, vulkanIbuf, vulkanUBObuf;
uint32_t ubo_offset = (uint32_t)curPipeline_->PushUBO(push_, vulkan_, &vulkanUBObuf);