• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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