2017-04-20 18:38:20 +00:00
|
|
|
// Copyright 2017 The NXT Authors
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
2017-07-06 18:41:13 +00:00
|
|
|
#include "backend/CommandBuffer.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2017-07-06 18:41:13 +00:00
|
|
|
#include "backend/BindGroup.h"
|
|
|
|
#include "backend/Buffer.h"
|
|
|
|
#include "backend/Commands.h"
|
|
|
|
#include "backend/CommandBufferStateTracker.h"
|
|
|
|
#include "backend/Device.h"
|
|
|
|
#include "backend/InputState.h"
|
|
|
|
#include "backend/Pipeline.h"
|
|
|
|
#include "backend/PipelineLayout.h"
|
|
|
|
#include "backend/Texture.h"
|
2017-04-20 18:38:20 +00:00
|
|
|
|
|
|
|
#include <cstring>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
namespace backend {
|
|
|
|
|
2017-06-26 15:43:51 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
bool ValidateCopyLocationFitsInTexture(CommandBufferBuilder* builder, const TextureCopyLocation& location) {
|
|
|
|
const TextureBase* texture = location.texture.Get();
|
|
|
|
if (location.level >= texture->GetNumMipLevels()) {
|
|
|
|
builder->HandleError("Copy mip-level out of range");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// All texture dimensions are in uint32_t so by doing checks in uint64_t we avoid overflows.
|
|
|
|
uint64_t level = location.level;
|
|
|
|
if (uint64_t(location.x) + uint64_t(location.width) > (static_cast<uint64_t>(texture->GetWidth()) >> level) ||
|
|
|
|
uint64_t(location.y) + uint64_t(location.height) > (static_cast<uint64_t>(texture->GetHeight()) >> level)) {
|
|
|
|
builder->HandleError("Copy would touch outside of the texture");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO(cwallez@chromium.org): Check the depth bound differently for 2D arrays and 3D textures
|
|
|
|
if (location.z != 0 || location.depth != 1) {
|
|
|
|
builder->HandleError("No support for z != 0 and depth != 1 for now");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FitsInBuffer(const BufferBase* buffer, uint32_t offset, uint32_t size) {
|
|
|
|
uint32_t bufferSize = buffer->GetSize();
|
|
|
|
return offset <= bufferSize && (size <= (bufferSize - offset));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ValidateCopySizeFitsInBuffer(CommandBufferBuilder* builder, const BufferCopyLocation& location, uint32_t dataSize) {
|
|
|
|
if (!FitsInBuffer(location.buffer.Get(), location.offset, dataSize)) {
|
|
|
|
builder->HandleError("Copy would overflow the buffer");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-07-07 18:39:38 +00:00
|
|
|
bool ComputeTextureCopyBufferSize(CommandBufferBuilder*, const TextureCopyLocation& location, uint32_t* bufferSize) {
|
2017-06-26 15:43:51 +00:00
|
|
|
// TODO(cwallez@chromium.org): check for overflows
|
2017-07-11 01:44:06 +00:00
|
|
|
uint32_t pixelSize = static_cast<uint32_t>(TextureFormatPixelSize(location.texture->GetFormat()));
|
2017-06-26 15:43:51 +00:00
|
|
|
*bufferSize = location.width * location.height * location.depth * pixelSize;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
CommandBufferBase::CommandBufferBase(CommandBufferBuilder* builder)
|
|
|
|
: device(builder->device),
|
2017-06-09 00:25:57 +00:00
|
|
|
buffersTransitioned(std::move(builder->state->buffersTransitioned)),
|
|
|
|
texturesTransitioned(std::move(builder->state->texturesTransitioned)) {
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool CommandBufferBase::ValidateResourceUsagesImmediate() {
|
|
|
|
for (auto buffer : buffersTransitioned) {
|
|
|
|
if (buffer->IsFrozen()) {
|
|
|
|
device->HandleError("Command buffer: cannot transition buffer with frozen usage");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (auto texture : texturesTransitioned) {
|
|
|
|
if (texture->IsFrozen()) {
|
|
|
|
device->HandleError("Command buffer: cannot transition texture with frozen usage");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FreeCommands(CommandIterator* commands) {
|
|
|
|
Command type;
|
|
|
|
while(commands->NextCommandId(&type)) {
|
|
|
|
switch (type) {
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::BeginComputePass:
|
|
|
|
{
|
|
|
|
BeginComputePassCmd* begin = commands->NextCommand<BeginComputePassCmd>();
|
|
|
|
begin->~BeginComputePassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-05-16 21:04:22 +00:00
|
|
|
case Command::BeginRenderPass:
|
|
|
|
{
|
|
|
|
BeginRenderPassCmd* begin = commands->NextCommand<BeginRenderPassCmd>();
|
|
|
|
begin->~BeginRenderPassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::BeginRenderSubpass:
|
|
|
|
{
|
|
|
|
BeginRenderSubpassCmd* begin = commands->NextCommand<BeginRenderSubpassCmd>();
|
|
|
|
begin->~BeginRenderSubpassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-06-12 22:12:29 +00:00
|
|
|
case Command::CopyBufferToBuffer:
|
|
|
|
{
|
|
|
|
CopyBufferToBufferCmd* copy = commands->NextCommand<CopyBufferToBufferCmd>();
|
|
|
|
copy->~CopyBufferToBufferCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::CopyBufferToTexture:
|
|
|
|
{
|
|
|
|
CopyBufferToTextureCmd* copy = commands->NextCommand<CopyBufferToTextureCmd>();
|
|
|
|
copy->~CopyBufferToTextureCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-06-26 20:23:03 +00:00
|
|
|
case Command::CopyTextureToBuffer:
|
|
|
|
{
|
|
|
|
CopyTextureToBufferCmd* copy = commands->NextCommand<CopyTextureToBufferCmd>();
|
|
|
|
copy->~CopyTextureToBufferCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::Dispatch:
|
|
|
|
{
|
|
|
|
DispatchCmd* dispatch = commands->NextCommand<DispatchCmd>();
|
|
|
|
dispatch->~DispatchCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::DrawArrays:
|
|
|
|
{
|
|
|
|
DrawArraysCmd* draw = commands->NextCommand<DrawArraysCmd>();
|
|
|
|
draw->~DrawArraysCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::DrawElements:
|
|
|
|
{
|
|
|
|
DrawElementsCmd* draw = commands->NextCommand<DrawElementsCmd>();
|
|
|
|
draw->~DrawElementsCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::EndComputePass:
|
|
|
|
{
|
|
|
|
EndComputePassCmd* cmd = commands->NextCommand<EndComputePassCmd>();
|
|
|
|
cmd->~EndComputePassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-05-16 21:04:22 +00:00
|
|
|
case Command::EndRenderPass:
|
|
|
|
{
|
|
|
|
EndRenderPassCmd* cmd = commands->NextCommand<EndRenderPassCmd>();
|
|
|
|
cmd->~EndRenderPassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::EndRenderSubpass:
|
|
|
|
{
|
|
|
|
EndRenderSubpassCmd* cmd = commands->NextCommand<EndRenderSubpassCmd>();
|
|
|
|
cmd->~EndRenderSubpassCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::SetPipeline:
|
|
|
|
{
|
|
|
|
SetPipelineCmd* cmd = commands->NextCommand<SetPipelineCmd>();
|
|
|
|
cmd->~SetPipelineCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::SetPushConstants:
|
|
|
|
{
|
|
|
|
SetPushConstantsCmd* cmd = commands->NextCommand<SetPushConstantsCmd>();
|
|
|
|
commands->NextData<uint32_t>(cmd->count);
|
|
|
|
cmd->~SetPushConstantsCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-05-31 00:03:44 +00:00
|
|
|
case Command::SetStencilReference:
|
|
|
|
{
|
|
|
|
SetStencilReferenceCmd* cmd = commands->NextCommand<SetStencilReferenceCmd>();
|
|
|
|
cmd->~SetStencilReferenceCmd();
|
|
|
|
}
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::SetBindGroup:
|
|
|
|
{
|
|
|
|
SetBindGroupCmd* cmd = commands->NextCommand<SetBindGroupCmd>();
|
|
|
|
cmd->~SetBindGroupCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::SetIndexBuffer:
|
|
|
|
{
|
|
|
|
SetIndexBufferCmd* cmd = commands->NextCommand<SetIndexBufferCmd>();
|
|
|
|
cmd->~SetIndexBufferCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::SetVertexBuffers:
|
|
|
|
{
|
|
|
|
SetVertexBuffersCmd* cmd = commands->NextCommand<SetVertexBuffersCmd>();
|
|
|
|
auto buffers = commands->NextData<Ref<BufferBase>>(cmd->count);
|
|
|
|
for (size_t i = 0; i < cmd->count; ++i) {
|
|
|
|
(&buffers[i])->~Ref<BufferBase>();
|
|
|
|
}
|
|
|
|
commands->NextData<uint32_t>(cmd->count);
|
|
|
|
cmd->~SetVertexBuffersCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::TransitionBufferUsage:
|
|
|
|
{
|
|
|
|
TransitionBufferUsageCmd* cmd = commands->NextCommand<TransitionBufferUsageCmd>();
|
|
|
|
cmd->~TransitionBufferUsageCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case Command::TransitionTextureUsage:
|
|
|
|
{
|
|
|
|
TransitionTextureUsageCmd* cmd = commands->NextCommand<TransitionTextureUsageCmd>();
|
|
|
|
cmd->~TransitionTextureUsageCmd();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
commands->DataWasDestroyed();
|
|
|
|
}
|
|
|
|
|
2017-06-16 18:26:26 +00:00
|
|
|
void SkipCommand(CommandIterator* commands, Command type) {
|
|
|
|
switch (type) {
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::BeginComputePass:
|
|
|
|
commands->NextCommand<BeginComputePassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-16 18:26:26 +00:00
|
|
|
case Command::BeginRenderPass:
|
|
|
|
commands->NextCommand<BeginRenderPassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::BeginRenderSubpass:
|
|
|
|
commands->NextCommand<BeginRenderSubpassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-16 18:26:26 +00:00
|
|
|
case Command::CopyBufferToBuffer:
|
|
|
|
commands->NextCommand<CopyBufferToBufferCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::CopyBufferToTexture:
|
|
|
|
commands->NextCommand<CopyBufferToTextureCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::CopyTextureToBuffer:
|
|
|
|
commands->NextCommand<CopyTextureToBufferCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::Dispatch:
|
|
|
|
commands->NextCommand<DispatchCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::DrawArrays:
|
|
|
|
commands->NextCommand<DrawArraysCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::DrawElements:
|
|
|
|
commands->NextCommand<DrawElementsCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::EndComputePass:
|
|
|
|
commands->NextCommand<EndComputePassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-16 18:26:26 +00:00
|
|
|
case Command::EndRenderPass:
|
|
|
|
commands->NextCommand<EndRenderPassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::EndRenderSubpass:
|
|
|
|
commands->NextCommand<EndRenderSubpassCmd>();
|
|
|
|
break;
|
|
|
|
|
2017-06-16 18:26:26 +00:00
|
|
|
case Command::SetPipeline:
|
|
|
|
commands->NextCommand<SetPipelineCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetPushConstants:
|
|
|
|
{
|
|
|
|
auto* cmd = commands->NextCommand<SetPushConstantsCmd>();
|
|
|
|
commands->NextData<uint32_t>(cmd->count);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetStencilReference:
|
|
|
|
commands->NextCommand<SetStencilReferenceCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetBindGroup:
|
|
|
|
commands->NextCommand<SetBindGroupCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetIndexBuffer:
|
|
|
|
commands->NextCommand<SetIndexBufferCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetVertexBuffers:
|
|
|
|
{
|
|
|
|
auto* cmd = commands->NextCommand<SetVertexBuffersCmd>();
|
|
|
|
commands->NextData<Ref<BufferBase>>(cmd->count);
|
|
|
|
commands->NextData<uint32_t>(cmd->count);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::TransitionBufferUsage:
|
|
|
|
commands->NextCommand<TransitionBufferUsageCmd>();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::TransitionTextureUsage:
|
|
|
|
commands->NextCommand<TransitionTextureUsageCmd>();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-09 00:25:57 +00:00
|
|
|
CommandBufferBuilder::CommandBufferBuilder(DeviceBase* device) : Builder(device), state(std::make_unique<CommandBufferStateTracker>(this)) {
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CommandBufferBuilder::~CommandBufferBuilder() {
|
2017-05-08 13:17:44 +00:00
|
|
|
if (!commandsAcquired) {
|
2017-04-20 18:38:20 +00:00
|
|
|
MoveToIterator();
|
|
|
|
FreeCommands(&iterator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CommandBufferBuilder::ValidateGetResult() {
|
|
|
|
MoveToIterator();
|
|
|
|
|
|
|
|
Command type;
|
2017-06-09 00:25:57 +00:00
|
|
|
while (iterator.NextCommandId(&type)) {
|
2017-04-20 18:38:20 +00:00
|
|
|
switch (type) {
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::BeginComputePass:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<BeginComputePassCmd>();
|
|
|
|
if (!state->BeginComputePass()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-05-16 21:04:22 +00:00
|
|
|
case Command::BeginRenderPass:
|
|
|
|
{
|
2017-06-09 00:25:57 +00:00
|
|
|
BeginRenderPassCmd* cmd = iterator.NextCommand<BeginRenderPassCmd>();
|
|
|
|
auto* renderPass = cmd->renderPass.Get();
|
|
|
|
auto* framebuffer = cmd->framebuffer.Get();
|
2017-06-09 01:25:14 +00:00
|
|
|
// TODO(kainino@chromium.org): null checks should not be necessary
|
|
|
|
if (renderPass == nullptr) {
|
|
|
|
HandleError("Render pass is invalid");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (framebuffer == nullptr) {
|
|
|
|
HandleError("Framebuffer is invalid");
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->BeginRenderPass(renderPass, framebuffer)) {
|
2017-05-16 21:04:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::BeginRenderSubpass:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<BeginRenderSubpassCmd>();
|
|
|
|
if (!state->BeginSubpass()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-06-12 22:12:29 +00:00
|
|
|
case Command::CopyBufferToBuffer:
|
|
|
|
{
|
|
|
|
CopyBufferToBufferCmd* copy = iterator.NextCommand<CopyBufferToBufferCmd>();
|
2017-06-26 15:43:51 +00:00
|
|
|
if (!ValidateCopySizeFitsInBuffer(this, copy->source, copy->size) ||
|
|
|
|
!ValidateCopySizeFitsInBuffer(this, copy->destination, copy->size) ||
|
|
|
|
!state->ValidateCanCopy() ||
|
|
|
|
!state->ValidateCanUseBufferAs(copy->source.buffer.Get(), nxt::BufferUsageBit::TransferSrc) ||
|
|
|
|
!state->ValidateCanUseBufferAs(copy->destination.buffer.Get(), nxt::BufferUsageBit::TransferDst)) {
|
2017-06-12 22:12:29 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::CopyBufferToTexture:
|
|
|
|
{
|
|
|
|
CopyBufferToTextureCmd* copy = iterator.NextCommand<CopyBufferToTextureCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
|
2017-06-26 15:43:51 +00:00
|
|
|
uint32_t bufferCopySize = 0;
|
|
|
|
if (!ComputeTextureCopyBufferSize(this, copy->destination, &bufferCopySize) ||
|
|
|
|
!ValidateCopyLocationFitsInTexture(this, copy->destination) ||
|
|
|
|
!ValidateCopySizeFitsInBuffer(this, copy->source, bufferCopySize) ||
|
|
|
|
!state->ValidateCanCopy() ||
|
|
|
|
!state->ValidateCanUseBufferAs(copy->source.buffer.Get(), nxt::BufferUsageBit::TransferSrc) ||
|
|
|
|
!state->ValidateCanUseTextureAs(copy->destination.texture.Get(), nxt::TextureUsageBit::TransferDst)) {
|
2017-06-09 00:25:57 +00:00
|
|
|
return false;
|
|
|
|
}
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-06-26 20:23:03 +00:00
|
|
|
case Command::CopyTextureToBuffer:
|
|
|
|
{
|
|
|
|
CopyTextureToBufferCmd* copy = iterator.NextCommand<CopyTextureToBufferCmd>();
|
|
|
|
|
|
|
|
uint32_t bufferCopySize = 0;
|
|
|
|
if (!ComputeTextureCopyBufferSize(this, copy->source, &bufferCopySize) ||
|
|
|
|
!ValidateCopyLocationFitsInTexture(this, copy->source) ||
|
|
|
|
!ValidateCopySizeFitsInBuffer(this, copy->destination, bufferCopySize) ||
|
|
|
|
!state->ValidateCanCopy() ||
|
|
|
|
!state->ValidateCanUseTextureAs(copy->source.texture.Get(), nxt::TextureUsageBit::TransferSrc) ||
|
|
|
|
!state->ValidateCanUseBufferAs(copy->destination.buffer.Get(), nxt::BufferUsageBit::TransferDst)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::Dispatch:
|
|
|
|
{
|
2017-06-09 00:25:57 +00:00
|
|
|
iterator.NextCommand<DispatchCmd>();
|
|
|
|
if (!state->ValidateCanDispatch()) {
|
|
|
|
return false;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::DrawArrays:
|
|
|
|
{
|
2017-06-09 00:25:57 +00:00
|
|
|
iterator.NextCommand<DrawArraysCmd>();
|
|
|
|
if (!state->ValidateCanDrawArrays()) {
|
|
|
|
return false;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
2017-06-09 00:25:57 +00:00
|
|
|
}
|
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
|
2017-06-09 00:25:57 +00:00
|
|
|
case Command::DrawElements:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<DrawElementsCmd>();
|
|
|
|
if (!state->ValidateCanDrawElements()) {
|
|
|
|
return false;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-07-10 21:07:24 +00:00
|
|
|
case Command::EndComputePass:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<EndComputePassCmd>();
|
|
|
|
if (!state->EndComputePass()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-05-16 21:04:22 +00:00
|
|
|
case Command::EndRenderPass:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<EndRenderPassCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->EndRenderPass()) {
|
2017-05-16 21:04:22 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-06-30 06:53:08 +00:00
|
|
|
case Command::EndRenderSubpass:
|
|
|
|
{
|
|
|
|
iterator.NextCommand<EndRenderSubpassCmd>();
|
|
|
|
if (!state->EndSubpass()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
case Command::SetPipeline:
|
|
|
|
{
|
|
|
|
SetPipelineCmd* cmd = iterator.NextCommand<SetPipelineCmd>();
|
|
|
|
PipelineBase* pipeline = cmd->pipeline.Get();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->SetPipeline(pipeline)) {
|
|
|
|
return false;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetPushConstants:
|
|
|
|
{
|
|
|
|
SetPushConstantsCmd* cmd = iterator.NextCommand<SetPushConstantsCmd>();
|
|
|
|
iterator.NextData<uint32_t>(cmd->count);
|
|
|
|
if (cmd->count + cmd->offset > kMaxPushConstants) {
|
2017-05-08 08:52:11 +00:00
|
|
|
HandleError("Setting pushconstants past the limit");
|
2017-04-20 18:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2017-05-31 00:03:44 +00:00
|
|
|
|
2017-05-30 22:13:03 +00:00
|
|
|
case Command::SetStencilReference:
|
2017-05-31 00:03:44 +00:00
|
|
|
{
|
2017-07-07 18:39:38 +00:00
|
|
|
iterator.NextCommand<SetStencilReferenceCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->HaveRenderPass()) {
|
2017-06-01 15:30:03 +00:00
|
|
|
HandleError("Can't set stencil reference without an active render pass");
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-31 00:03:44 +00:00
|
|
|
}
|
2017-05-30 22:13:03 +00:00
|
|
|
break;
|
2017-04-20 18:38:20 +00:00
|
|
|
|
|
|
|
case Command::SetBindGroup:
|
|
|
|
{
|
|
|
|
SetBindGroupCmd* cmd = iterator.NextCommand<SetBindGroupCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->SetBindGroup(cmd->index, cmd->group.Get())) {
|
2017-04-20 18:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetIndexBuffer:
|
|
|
|
{
|
|
|
|
SetIndexBufferCmd* cmd = iterator.NextCommand<SetIndexBufferCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->SetIndexBuffer(cmd->buffer.Get())) {
|
2017-04-20 18:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::SetVertexBuffers:
|
|
|
|
{
|
|
|
|
SetVertexBuffersCmd* cmd = iterator.NextCommand<SetVertexBuffersCmd>();
|
|
|
|
auto buffers = iterator.NextData<Ref<BufferBase>>(cmd->count);
|
|
|
|
iterator.NextData<uint32_t>(cmd->count);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cmd->count; ++i) {
|
2017-06-09 00:25:57 +00:00
|
|
|
state->SetVertexBuffer(cmd->startSlot + i, buffers[i].Get());
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::TransitionBufferUsage:
|
|
|
|
{
|
|
|
|
TransitionBufferUsageCmd* cmd = iterator.NextCommand<TransitionBufferUsageCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->TransitionBufferUsage(cmd->buffer.Get(), cmd->usage)) {
|
2017-04-20 18:38:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Command::TransitionTextureUsage:
|
|
|
|
{
|
|
|
|
TransitionTextureUsageCmd* cmd = iterator.NextCommand<TransitionTextureUsageCmd>();
|
2017-06-09 00:25:57 +00:00
|
|
|
if (!state->TransitionTextureUsage(cmd->texture.Get(), cmd->usage)) {
|
2017-05-24 20:07:30 +00:00
|
|
|
return false;
|
2017-05-16 21:04:22 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-09 01:25:14 +00:00
|
|
|
if (!state->ValidateEndCommandBuffer()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
CommandIterator CommandBufferBuilder::AcquireCommands() {
|
2017-05-08 13:17:44 +00:00
|
|
|
ASSERT(!commandsAcquired);
|
|
|
|
commandsAcquired = true;
|
2017-04-20 18:38:20 +00:00
|
|
|
return std::move(iterator);
|
|
|
|
}
|
|
|
|
|
2017-05-08 13:17:44 +00:00
|
|
|
CommandBufferBase* CommandBufferBuilder::GetResultImpl() {
|
2017-04-20 18:38:20 +00:00
|
|
|
MoveToIterator();
|
|
|
|
return device->CreateCommandBuffer(this);
|
|
|
|
}
|
|
|
|
|
2017-07-10 21:07:24 +00:00
|
|
|
void CommandBufferBuilder::BeginComputePass() {
|
|
|
|
allocator.Allocate<BeginComputePassCmd>(Command::BeginComputePass);
|
2017-05-16 21:04:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::BeginRenderPass(RenderPassBase* renderPass, FramebufferBase* framebuffer) {
|
|
|
|
BeginRenderPassCmd* cmd = allocator.Allocate<BeginRenderPassCmd>(Command::BeginRenderPass);
|
|
|
|
new(cmd) BeginRenderPassCmd;
|
|
|
|
cmd->renderPass = renderPass;
|
|
|
|
cmd->framebuffer = framebuffer;
|
|
|
|
}
|
|
|
|
|
2017-07-10 21:07:24 +00:00
|
|
|
void CommandBufferBuilder::BeginRenderSubpass() {
|
|
|
|
allocator.Allocate<BeginRenderSubpassCmd>(Command::BeginRenderSubpass);
|
|
|
|
}
|
|
|
|
|
2017-06-12 22:12:29 +00:00
|
|
|
void CommandBufferBuilder::CopyBufferToBuffer(BufferBase* source, uint32_t sourceOffset, BufferBase* destination, uint32_t destinationOffset, uint32_t size) {
|
|
|
|
CopyBufferToBufferCmd* copy = allocator.Allocate<CopyBufferToBufferCmd>(Command::CopyBufferToBuffer);
|
|
|
|
new(copy) CopyBufferToBufferCmd;
|
2017-06-26 15:43:51 +00:00
|
|
|
copy->source.buffer = source;
|
|
|
|
copy->source.offset = sourceOffset;
|
|
|
|
copy->destination.buffer = destination;
|
|
|
|
copy->destination.offset = destinationOffset;
|
2017-06-12 22:12:29 +00:00
|
|
|
copy->size = size;
|
|
|
|
}
|
|
|
|
|
2017-05-09 14:57:52 +00:00
|
|
|
void CommandBufferBuilder::CopyBufferToTexture(BufferBase* buffer, uint32_t bufferOffset,
|
|
|
|
TextureBase* texture, uint32_t x, uint32_t y, uint32_t z,
|
2017-04-20 18:38:20 +00:00
|
|
|
uint32_t width, uint32_t height, uint32_t depth, uint32_t level) {
|
|
|
|
CopyBufferToTextureCmd* copy = allocator.Allocate<CopyBufferToTextureCmd>(Command::CopyBufferToTexture);
|
|
|
|
new(copy) CopyBufferToTextureCmd;
|
2017-06-26 15:43:51 +00:00
|
|
|
copy->source.buffer = buffer;
|
|
|
|
copy->source.offset = bufferOffset;
|
|
|
|
copy->destination.texture = texture;
|
|
|
|
copy->destination.x = x;
|
|
|
|
copy->destination.y = y;
|
|
|
|
copy->destination.z = z;
|
|
|
|
copy->destination.width = width;
|
|
|
|
copy->destination.height = height;
|
|
|
|
copy->destination.depth = depth;
|
|
|
|
copy->destination.level = level;
|
2017-04-20 18:38:20 +00:00
|
|
|
}
|
|
|
|
|
2017-06-26 20:23:03 +00:00
|
|
|
void CommandBufferBuilder::CopyTextureToBuffer(TextureBase* texture, uint32_t x, uint32_t y, uint32_t z,
|
|
|
|
uint32_t width, uint32_t height, uint32_t depth, uint32_t level,
|
|
|
|
BufferBase* buffer, uint32_t bufferOffset) {
|
|
|
|
CopyTextureToBufferCmd* copy = allocator.Allocate<CopyTextureToBufferCmd>(Command::CopyTextureToBuffer);
|
|
|
|
new(copy) CopyTextureToBufferCmd;
|
|
|
|
copy->source.texture = texture;
|
|
|
|
copy->source.x = x;
|
|
|
|
copy->source.y = y;
|
|
|
|
copy->source.z = z;
|
|
|
|
copy->source.width = width;
|
|
|
|
copy->source.height = height;
|
|
|
|
copy->source.depth = depth;
|
|
|
|
copy->source.level = level;
|
|
|
|
copy->destination.buffer = buffer;
|
|
|
|
copy->destination.offset = bufferOffset;
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
void CommandBufferBuilder::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
|
|
|
|
DispatchCmd* dispatch = allocator.Allocate<DispatchCmd>(Command::Dispatch);
|
|
|
|
new(dispatch) DispatchCmd;
|
|
|
|
dispatch->x = x;
|
|
|
|
dispatch->y = y;
|
|
|
|
dispatch->z = z;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::DrawArrays(uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance) {
|
|
|
|
DrawArraysCmd* draw = allocator.Allocate<DrawArraysCmd>(Command::DrawArrays);
|
|
|
|
new(draw) DrawArraysCmd;
|
|
|
|
draw->vertexCount = vertexCount;
|
|
|
|
draw->instanceCount = instanceCount;
|
|
|
|
draw->firstVertex = firstVertex;
|
|
|
|
draw->firstInstance = firstInstance;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::DrawElements(uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, uint32_t firstInstance) {
|
|
|
|
DrawElementsCmd* draw = allocator.Allocate<DrawElementsCmd>(Command::DrawElements);
|
|
|
|
new(draw) DrawElementsCmd;
|
|
|
|
draw->indexCount = indexCount;
|
|
|
|
draw->instanceCount = instanceCount;
|
|
|
|
draw->firstIndex = firstIndex;
|
|
|
|
draw->firstInstance = firstInstance;
|
|
|
|
}
|
|
|
|
|
2017-07-10 21:07:24 +00:00
|
|
|
void CommandBufferBuilder::EndComputePass() {
|
|
|
|
allocator.Allocate<EndComputePassCmd>(Command::EndComputePass);
|
|
|
|
}
|
|
|
|
|
2017-05-16 21:04:22 +00:00
|
|
|
void CommandBufferBuilder::EndRenderPass() {
|
|
|
|
allocator.Allocate<EndRenderPassCmd>(Command::EndRenderPass);
|
|
|
|
}
|
|
|
|
|
2017-06-30 06:53:08 +00:00
|
|
|
void CommandBufferBuilder::EndRenderSubpass() {
|
|
|
|
allocator.Allocate<EndRenderSubpassCmd>(Command::EndRenderSubpass);
|
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
void CommandBufferBuilder::SetPipeline(PipelineBase* pipeline) {
|
|
|
|
SetPipelineCmd* cmd = allocator.Allocate<SetPipelineCmd>(Command::SetPipeline);
|
|
|
|
new(cmd) SetPipelineCmd;
|
|
|
|
cmd->pipeline = pipeline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::SetPushConstants(nxt::ShaderStageBit stage, uint32_t offset, uint32_t count, const void* data) {
|
|
|
|
if (offset + count > kMaxPushConstants) {
|
2017-05-08 08:52:11 +00:00
|
|
|
HandleError("Setting too many push constants");
|
2017-04-20 18:38:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetPushConstantsCmd* cmd = allocator.Allocate<SetPushConstantsCmd>(Command::SetPushConstants);
|
|
|
|
new(cmd) SetPushConstantsCmd;
|
|
|
|
cmd->stage = stage;
|
|
|
|
cmd->offset = offset;
|
|
|
|
cmd->count = count;
|
|
|
|
|
|
|
|
uint32_t* values = allocator.AllocateData<uint32_t>(count);
|
|
|
|
memcpy(values, data, count * sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
|
2017-06-01 15:30:03 +00:00
|
|
|
void CommandBufferBuilder::SetStencilReference(uint32_t reference) {
|
2017-05-30 22:13:03 +00:00
|
|
|
SetStencilReferenceCmd* cmd = allocator.Allocate<SetStencilReferenceCmd>(Command::SetStencilReference);
|
|
|
|
new(cmd) SetStencilReferenceCmd;
|
2017-06-01 15:30:03 +00:00
|
|
|
cmd->reference = reference;
|
2017-05-30 22:13:03 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 18:38:20 +00:00
|
|
|
void CommandBufferBuilder::SetBindGroup(uint32_t groupIndex, BindGroupBase* group) {
|
|
|
|
if (groupIndex >= kMaxBindGroups) {
|
2017-05-08 08:52:11 +00:00
|
|
|
HandleError("Setting bind group over the max");
|
2017-04-20 18:38:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetBindGroupCmd* cmd = allocator.Allocate<SetBindGroupCmd>(Command::SetBindGroup);
|
|
|
|
new(cmd) SetBindGroupCmd;
|
|
|
|
cmd->index = groupIndex;
|
|
|
|
cmd->group = group;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::SetIndexBuffer(BufferBase* buffer, uint32_t offset, nxt::IndexFormat format) {
|
|
|
|
// TODO(kainino@chromium.org): validation
|
|
|
|
|
|
|
|
SetIndexBufferCmd* cmd = allocator.Allocate<SetIndexBufferCmd>(Command::SetIndexBuffer);
|
|
|
|
new(cmd) SetIndexBufferCmd;
|
|
|
|
cmd->buffer = buffer;
|
|
|
|
cmd->offset = offset;
|
|
|
|
cmd->format = format;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::SetVertexBuffers(uint32_t startSlot, uint32_t count, BufferBase* const* buffers, uint32_t const* offsets){
|
|
|
|
// TODO(kainino@chromium.org): validation
|
|
|
|
|
|
|
|
SetVertexBuffersCmd* cmd = allocator.Allocate<SetVertexBuffersCmd>(Command::SetVertexBuffers);
|
|
|
|
new(cmd) SetVertexBuffersCmd;
|
|
|
|
cmd->startSlot = startSlot;
|
|
|
|
cmd->count = count;
|
|
|
|
|
|
|
|
Ref<BufferBase>* cmdBuffers = allocator.AllocateData<Ref<BufferBase>>(count);
|
|
|
|
for (size_t i = 0; i < count; ++i) {
|
|
|
|
new(&cmdBuffers[i]) Ref<BufferBase>(buffers[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t* cmdOffsets = allocator.AllocateData<uint32_t>(count);
|
|
|
|
memcpy(cmdOffsets, offsets, count * sizeof(uint32_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::TransitionBufferUsage(BufferBase* buffer, nxt::BufferUsageBit usage) {
|
|
|
|
TransitionBufferUsageCmd* cmd = allocator.Allocate<TransitionBufferUsageCmd>(Command::TransitionBufferUsage);
|
|
|
|
new(cmd) TransitionBufferUsageCmd;
|
|
|
|
cmd->buffer = buffer;
|
|
|
|
cmd->usage = usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::TransitionTextureUsage(TextureBase* texture, nxt::TextureUsageBit usage) {
|
|
|
|
TransitionTextureUsageCmd* cmd = allocator.Allocate<TransitionTextureUsageCmd>(Command::TransitionTextureUsage);
|
|
|
|
new(cmd) TransitionTextureUsageCmd;
|
|
|
|
cmd->texture = texture;
|
|
|
|
cmd->usage = usage;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CommandBufferBuilder::MoveToIterator() {
|
|
|
|
if (!movedToIterator) {
|
|
|
|
iterator = std::move(allocator);
|
|
|
|
movedToIterator = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|