1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/CommandBuffer.h" 16 17 #include "common/BitSetIterator.h" 18 #include "dawn_native/Buffer.h" 19 #include "dawn_native/CommandEncoder.h" 20 #include "dawn_native/CommandValidation.h" 21 #include "dawn_native/Commands.h" 22 #include "dawn_native/Format.h" 23 #include "dawn_native/ObjectType_autogen.h" 24 #include "dawn_native/Texture.h" 25 26 namespace dawn_native { 27 CommandBufferBase(CommandEncoder * encoder,const CommandBufferDescriptor * descriptor)28 CommandBufferBase::CommandBufferBase(CommandEncoder* encoder, 29 const CommandBufferDescriptor* descriptor) 30 : ApiObjectBase(encoder->GetDevice(), descriptor->label), 31 mCommands(encoder->AcquireCommands()), 32 mResourceUsages(encoder->AcquireResourceUsages()) { 33 TrackInDevice(); 34 } 35 CommandBufferBase(DeviceBase * device)36 CommandBufferBase::CommandBufferBase(DeviceBase* device) 37 : ApiObjectBase(device, kLabelNotImplemented) { 38 TrackInDevice(); 39 } 40 CommandBufferBase(DeviceBase * device,ObjectBase::ErrorTag tag)41 CommandBufferBase::CommandBufferBase(DeviceBase* device, ObjectBase::ErrorTag tag) 42 : ApiObjectBase(device, tag) { 43 } 44 45 // static MakeError(DeviceBase * device)46 CommandBufferBase* CommandBufferBase::MakeError(DeviceBase* device) { 47 return new CommandBufferBase(device, ObjectBase::kError); 48 } 49 GetType() const50 ObjectType CommandBufferBase::GetType() const { 51 return ObjectType::CommandBuffer; 52 } 53 ValidateCanUseInSubmitNow() const54 MaybeError CommandBufferBase::ValidateCanUseInSubmitNow() const { 55 ASSERT(!IsError()); 56 57 DAWN_INVALID_IF(!IsAlive(), "%s cannot be submitted more than once.", this); 58 return {}; 59 } 60 DestroyImpl()61 void CommandBufferBase::DestroyImpl() { 62 FreeCommands(&mCommands); 63 mResourceUsages = {}; 64 } 65 GetResourceUsages() const66 const CommandBufferResourceUsage& CommandBufferBase::GetResourceUsages() const { 67 return mResourceUsages; 68 } 69 GetCommandIteratorForTesting()70 CommandIterator* CommandBufferBase::GetCommandIteratorForTesting() { 71 return &mCommands; 72 } 73 IsCompleteSubresourceCopiedTo(const TextureBase * texture,const Extent3D copySize,const uint32_t mipLevel)74 bool IsCompleteSubresourceCopiedTo(const TextureBase* texture, 75 const Extent3D copySize, 76 const uint32_t mipLevel) { 77 Extent3D extent = texture->GetMipLevelPhysicalSize(mipLevel); 78 79 ASSERT(texture->GetDimension() != wgpu::TextureDimension::e1D); 80 switch (texture->GetDimension()) { 81 case wgpu::TextureDimension::e2D: 82 return extent.width == copySize.width && extent.height == copySize.height; 83 case wgpu::TextureDimension::e3D: 84 return extent.width == copySize.width && extent.height == copySize.height && 85 extent.depthOrArrayLayers == copySize.depthOrArrayLayers; 86 default: 87 UNREACHABLE(); 88 } 89 } 90 GetSubresourcesAffectedByCopy(const TextureCopy & copy,const Extent3D & copySize)91 SubresourceRange GetSubresourcesAffectedByCopy(const TextureCopy& copy, 92 const Extent3D& copySize) { 93 switch (copy.texture->GetDimension()) { 94 case wgpu::TextureDimension::e2D: 95 return { 96 copy.aspect, {copy.origin.z, copySize.depthOrArrayLayers}, {copy.mipLevel, 1}}; 97 case wgpu::TextureDimension::e3D: 98 return {copy.aspect, {0, 1}, {copy.mipLevel, 1}}; 99 default: 100 UNREACHABLE(); 101 } 102 } 103 LazyClearRenderPassAttachments(BeginRenderPassCmd * renderPass)104 void LazyClearRenderPassAttachments(BeginRenderPassCmd* renderPass) { 105 for (ColorAttachmentIndex i : 106 IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) { 107 auto& attachmentInfo = renderPass->colorAttachments[i]; 108 TextureViewBase* view = attachmentInfo.view.Get(); 109 bool hasResolveTarget = attachmentInfo.resolveTarget != nullptr; 110 111 ASSERT(view->GetLayerCount() == 1); 112 ASSERT(view->GetLevelCount() == 1); 113 SubresourceRange range = view->GetSubresourceRange(); 114 115 // If the loadOp is Load, but the subresource is not initialized, use Clear instead. 116 if (attachmentInfo.loadOp == wgpu::LoadOp::Load && 117 !view->GetTexture()->IsSubresourceContentInitialized(range)) { 118 attachmentInfo.loadOp = wgpu::LoadOp::Clear; 119 attachmentInfo.clearColor = {0.f, 0.f, 0.f, 0.f}; 120 } 121 122 if (hasResolveTarget) { 123 // We need to set the resolve target to initialized so that it does not get 124 // cleared later in the pipeline. The texture will be resolved from the 125 // source color attachment, which will be correctly initialized. 126 TextureViewBase* resolveView = attachmentInfo.resolveTarget.Get(); 127 ASSERT(resolveView->GetLayerCount() == 1); 128 ASSERT(resolveView->GetLevelCount() == 1); 129 resolveView->GetTexture()->SetIsSubresourceContentInitialized( 130 true, resolveView->GetSubresourceRange()); 131 } 132 133 switch (attachmentInfo.storeOp) { 134 case wgpu::StoreOp::Store: 135 view->GetTexture()->SetIsSubresourceContentInitialized(true, range); 136 break; 137 138 case wgpu::StoreOp::Discard: 139 view->GetTexture()->SetIsSubresourceContentInitialized(false, range); 140 break; 141 } 142 } 143 144 if (renderPass->attachmentState->HasDepthStencilAttachment()) { 145 auto& attachmentInfo = renderPass->depthStencilAttachment; 146 TextureViewBase* view = attachmentInfo.view.Get(); 147 ASSERT(view->GetLayerCount() == 1); 148 ASSERT(view->GetLevelCount() == 1); 149 SubresourceRange range = view->GetSubresourceRange(); 150 151 SubresourceRange depthRange = range; 152 depthRange.aspects = range.aspects & Aspect::Depth; 153 154 SubresourceRange stencilRange = range; 155 stencilRange.aspects = range.aspects & Aspect::Stencil; 156 157 // If the depth stencil texture has not been initialized, we want to use loadop 158 // clear to init the contents to 0's 159 if (!view->GetTexture()->IsSubresourceContentInitialized(depthRange) && 160 attachmentInfo.depthLoadOp == wgpu::LoadOp::Load) { 161 attachmentInfo.clearDepth = 0.0f; 162 attachmentInfo.depthLoadOp = wgpu::LoadOp::Clear; 163 } 164 165 if (!view->GetTexture()->IsSubresourceContentInitialized(stencilRange) && 166 attachmentInfo.stencilLoadOp == wgpu::LoadOp::Load) { 167 attachmentInfo.clearStencil = 0u; 168 attachmentInfo.stencilLoadOp = wgpu::LoadOp::Clear; 169 } 170 171 view->GetTexture()->SetIsSubresourceContentInitialized( 172 attachmentInfo.depthStoreOp == wgpu::StoreOp::Store, depthRange); 173 174 view->GetTexture()->SetIsSubresourceContentInitialized( 175 attachmentInfo.stencilStoreOp == wgpu::StoreOp::Store, stencilRange); 176 } 177 } 178 IsFullBufferOverwrittenInTextureToBufferCopy(const CopyTextureToBufferCmd * copy)179 bool IsFullBufferOverwrittenInTextureToBufferCopy(const CopyTextureToBufferCmd* copy) { 180 ASSERT(copy != nullptr); 181 182 if (copy->destination.offset > 0) { 183 // The copy doesn't touch the start of the buffer. 184 return false; 185 } 186 187 const TextureBase* texture = copy->source.texture.Get(); 188 const TexelBlockInfo& blockInfo = 189 texture->GetFormat().GetAspectInfo(copy->source.aspect).block; 190 const uint64_t widthInBlocks = copy->copySize.width / blockInfo.width; 191 const uint64_t heightInBlocks = copy->copySize.height / blockInfo.height; 192 const bool multiSlice = copy->copySize.depthOrArrayLayers > 1; 193 const bool multiRow = multiSlice || heightInBlocks > 1; 194 195 if (multiSlice && copy->destination.rowsPerImage > heightInBlocks) { 196 // There are gaps between slices that aren't overwritten 197 return false; 198 } 199 200 const uint64_t copyTextureDataSizePerRow = widthInBlocks * blockInfo.byteSize; 201 if (multiRow && copy->destination.bytesPerRow > copyTextureDataSizePerRow) { 202 // There are gaps between rows that aren't overwritten 203 return false; 204 } 205 206 // After the above checks, we're sure the copy has no gaps. 207 // Now, compute the total number of bytes written. 208 const uint64_t writtenBytes = 209 ComputeRequiredBytesInCopy(blockInfo, copy->copySize, copy->destination.bytesPerRow, 210 copy->destination.rowsPerImage) 211 .AcquireSuccess(); 212 if (!copy->destination.buffer->IsFullBufferRange(copy->destination.offset, writtenBytes)) { 213 // The written bytes don't cover the whole buffer. 214 return false; 215 } 216 217 return true; 218 } 219 ConvertToFloatColor(dawn_native::Color color)220 std::array<float, 4> ConvertToFloatColor(dawn_native::Color color) { 221 const std::array<float, 4> outputValue = { 222 static_cast<float>(color.r), static_cast<float>(color.g), static_cast<float>(color.b), 223 static_cast<float>(color.a)}; 224 return outputValue; 225 } ConvertToSignedIntegerColor(dawn_native::Color color)226 std::array<int32_t, 4> ConvertToSignedIntegerColor(dawn_native::Color color) { 227 const std::array<int32_t, 4> outputValue = { 228 static_cast<int32_t>(color.r), static_cast<int32_t>(color.g), 229 static_cast<int32_t>(color.b), static_cast<int32_t>(color.a)}; 230 return outputValue; 231 } 232 ConvertToUnsignedIntegerColor(dawn_native::Color color)233 std::array<uint32_t, 4> ConvertToUnsignedIntegerColor(dawn_native::Color color) { 234 const std::array<uint32_t, 4> outputValue = { 235 static_cast<uint32_t>(color.r), static_cast<uint32_t>(color.g), 236 static_cast<uint32_t>(color.b), static_cast<uint32_t>(color.a)}; 237 return outputValue; 238 } 239 240 } // namespace dawn_native 241