• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
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 
16 #include "render_staging.h"
17 
18 #include <cinttypes>
19 
20 #include <render/datastore/intf_render_data_store_manager.h>
21 #include <render/device/intf_gpu_resource_manager.h>
22 #include <render/namespace.h>
23 #include <render/nodecontext/intf_node_context_pso_manager.h>
24 #include <render/nodecontext/intf_render_command_list.h>
25 #include <render/nodecontext/intf_render_node_context_manager.h>
26 
27 #include "datastore/render_data_store_default_staging.h"
28 #include "util/log.h"
29 
30 using namespace BASE_NS;
31 
32 RENDER_BEGIN_NAMESPACE()
33 namespace {
34 constexpr uint32_t MIP_MAP_TILING_FEATURES { CORE_FORMAT_FEATURE_BLIT_DST_BIT | CORE_FORMAT_FEATURE_BLIT_SRC_BIT };
35 
ExplicitBarrierUndefinedImageToTransferDst(IRenderCommandList & cmdList,const RenderHandle handle)36 void ExplicitBarrierUndefinedImageToTransferDst(IRenderCommandList& cmdList, const RenderHandle handle)
37 {
38     const ImageResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
39         PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
40         ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED }; // NOTE: undefined, because we do not care the previous data
41     const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
42         PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT, ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
43     const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
44         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
45     cmdList.CustomImageBarrier(handle, src, dst, imageSubresourceRange);
46     cmdList.AddCustomBarrierPoint();
47 }
48 
ExplicitBarrierTransferDstImageToTransferSrc(IRenderCommandList & cmdList,const RenderHandle handle)49 void ExplicitBarrierTransferDstImageToTransferSrc(IRenderCommandList& cmdList, const RenderHandle handle)
50 {
51     const ImageResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
52         PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT, ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
53     const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
54         PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT, ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
55     const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
56         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
57     cmdList.CustomImageBarrier(handle, src, dst, imageSubresourceRange);
58     cmdList.AddCustomBarrierPoint();
59 }
60 
BlitScalingImage(IRenderCommandList & cmdList,const BufferImageCopy & copy,const RenderHandle srcHandle,const RenderHandle dstHandle,const GpuImageDesc & dstImageDesc)61 void BlitScalingImage(IRenderCommandList& cmdList, const BufferImageCopy& copy, const RenderHandle srcHandle,
62     const RenderHandle dstHandle, const GpuImageDesc& dstImageDesc)
63 {
64     const ImageBlit imageBlit {
65         {
66             ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
67             0,
68             0,
69             1,
70         },
71         {
72             { 0, 0, 0 },
73             { copy.imageExtent.width, copy.imageExtent.height, 1 },
74         },
75         {
76             ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
77             0,
78             0,
79             1,
80         },
81         {
82             { 0, 0, 0 },
83             { dstImageDesc.width, dstImageDesc.height, 1 },
84         },
85     };
86     constexpr Filter filter = Filter::CORE_FILTER_LINEAR;
87     cmdList.BlitImage(srcHandle, dstHandle, imageBlit, filter);
88 }
89 
GetMipLevelSize(uint32_t originalSize,uint32_t mipLevel)90 uint32_t GetMipLevelSize(uint32_t originalSize, uint32_t mipLevel)
91 {
92     const uint32_t mipSize = originalSize >> mipLevel;
93     return mipSize >= 1u ? mipSize : 1u;
94 }
95 
GenerateMipmaps(IRenderCommandList & cmdList,const GpuImageDesc & imageDesc,const RenderHandle mipImageHandle,const uint32_t currentMipLevel)96 void GenerateMipmaps(IRenderCommandList& cmdList, const GpuImageDesc& imageDesc, const RenderHandle mipImageHandle,
97     const uint32_t currentMipLevel)
98 {
99     constexpr Filter filter = Filter::CORE_FILTER_LINEAR;
100     const uint32_t mipCount = imageDesc.mipCount;
101     const uint32_t layerCount = imageDesc.layerCount;
102 
103     const uint32_t iw = imageDesc.width;
104     const uint32_t ih = imageDesc.height;
105     for (uint32_t mipIdx = currentMipLevel + 1; mipIdx < mipCount; ++mipIdx) {
106         const uint32_t dstMipLevel = mipIdx;
107         const uint32_t srcMipLevel = dstMipLevel - 1;
108         // explicit transition for src mip
109         {
110             const ImageResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
111                 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
112                 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
113             const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
114                 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
115                 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
116             const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
117                 srcMipLevel, 1, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
118             cmdList.CustomImageBarrier(mipImageHandle, src, dst, imageSubresourceRange);
119             cmdList.AddCustomBarrierPoint();
120         }
121         {
122             const ImageBlit imageBlit {
123                 {
124                     ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
125                     srcMipLevel,
126                     0,
127                     layerCount,
128                 },
129                 {
130                     { 0, 0, 0 },
131                     { GetMipLevelSize(iw, srcMipLevel), GetMipLevelSize(ih, srcMipLevel), 1 },
132                 },
133                 {
134                     ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
135                     dstMipLevel,
136                     0,
137                     layerCount,
138                 },
139                 {
140                     { 0, 0, 0 },
141                     { GetMipLevelSize(iw, dstMipLevel), GetMipLevelSize(ih, dstMipLevel), 1 },
142                 },
143             };
144             cmdList.BlitImage(mipImageHandle, mipImageHandle, imageBlit, filter);
145 
146             // explicit "out" transition for src mip to dst to enable easy all mip transition in the end
147             {
148                 const ImageResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
149                     PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
150                     ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
151                 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
152                     PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
153                     ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
154                 const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT,
155                     srcMipLevel, 1, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
156                 cmdList.CustomImageBarrier(mipImageHandle, src, dst, imageSubresourceRange);
157                 cmdList.AddCustomBarrierPoint();
158             }
159         }
160     }
161 }
162 
CopyBuffersToImages(const IRenderNodeGpuResourceManager & gpuResourceMgr,IRenderCommandList & cmdList,const vector<StagingCopyStruct> & bufferToImage,const vector<BufferImageCopy> & bufferImageCopies,const ScalingImageDataStruct & scalingImageData)163 void CopyBuffersToImages(const IRenderNodeGpuResourceManager& gpuResourceMgr, IRenderCommandList& cmdList,
164     const vector<StagingCopyStruct>& bufferToImage, const vector<BufferImageCopy>& bufferImageCopies,
165     const ScalingImageDataStruct& scalingImageData)
166 {
167     for (const auto& ref : bufferToImage) {
168         if (ref.invalidOperation) {
169             continue;
170         }
171         const uint32_t beginIndex = ref.beginIndex;
172         const uint32_t count = ref.count;
173         for (uint32_t idx = 0; idx < count; ++idx) {
174             const BufferImageCopy& copyRef = bufferImageCopies[beginIndex + idx];
175             // barriers are only done for dynamic resources automatically (e.g. when copying to same image multiple
176             // times)
177             // NOTE: add desc to data (so we do not need to lock gpu resource manager)
178             const GpuImageDesc imageDesc = gpuResourceMgr.GetImageDescriptor(ref.dstHandle.GetHandle());
179             RenderHandle bufferToImageDst = ref.dstHandle.GetHandle();
180             bool useScaling = false;
181             if (ref.format != Format::BASE_FORMAT_UNDEFINED) {
182                 if (const auto iter = scalingImageData.formatToScalingImages.find(ref.format);
183                     iter != scalingImageData.formatToScalingImages.cend()) {
184                     PLUGIN_ASSERT(iter->second < scalingImageData.scalingImages.size());
185                     bufferToImageDst = scalingImageData.scalingImages[iter->second].handle.GetHandle();
186                     ExplicitBarrierUndefinedImageToTransferDst(cmdList, bufferToImageDst);
187                     useScaling = true;
188                 }
189             }
190             cmdList.CopyBufferToImage(ref.srcHandle.GetHandle(), bufferToImageDst, copyRef);
191             if (useScaling) {
192                 ExplicitBarrierTransferDstImageToTransferSrc(cmdList, bufferToImageDst);
193                 BlitScalingImage(cmdList, copyRef, bufferToImageDst, ref.dstHandle.GetHandle(), imageDesc);
194             }
195 
196             // generate mips
197             if (imageDesc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS) {
198                 const FormatProperties formatProperties = gpuResourceMgr.GetFormatProperties(imageDesc.format);
199                 if ((formatProperties.optimalTilingFeatures & MIP_MAP_TILING_FEATURES) == MIP_MAP_TILING_FEATURES) {
200                     const uint32_t mipCount = imageDesc.mipCount;
201                     const uint32_t availableMipCount = ref.count;
202                     const uint32_t currentMipLevel = copyRef.imageSubresource.mipLevel;
203 
204                     const bool isLastAvailableMipLevel = (currentMipLevel + 1) == availableMipCount;
205                     const bool isMissingMipLevels = availableMipCount < mipCount;
206 
207                     if (isMissingMipLevels && isLastAvailableMipLevel) {
208                         GenerateMipmaps(
209                             cmdList, imageDesc, ref.dstHandle.GetHandle(), copyRef.imageSubresource.mipLevel);
210                     }
211                 }
212 #if (RENDER_VALIDATION_ENABLED == 1)
213                 if ((formatProperties.optimalTilingFeatures & MIP_MAP_TILING_FEATURES) != MIP_MAP_TILING_FEATURES) {
214                     PLUGIN_LOG_ONCE_W("core_validation_auto_mipmapping",
215                         "RENDER_VALIDATION: requested automatic mip mapping not done for format: %u", imageDesc.format);
216                 }
217 #endif
218             }
219         }
220     }
221 }
222 
CopyImagesToBuffersImpl(IRenderCommandList & cmdList,const vector<StagingCopyStruct> & imageToBuffer,const vector<BufferImageCopy> & bufferImageCopies)223 void CopyImagesToBuffersImpl(IRenderCommandList& cmdList, const vector<StagingCopyStruct>& imageToBuffer,
224     const vector<BufferImageCopy>& bufferImageCopies)
225 {
226     for (const auto& ref : imageToBuffer) {
227         if (ref.invalidOperation) {
228             continue;
229         }
230         const uint32_t beginIndex = ref.beginIndex;
231         const uint32_t count = ref.count;
232         for (uint32_t idx = 0; idx < count; ++idx) {
233             const BufferImageCopy& copyRef = bufferImageCopies[beginIndex + idx];
234             cmdList.CopyImageToBuffer(ref.srcHandle.GetHandle(), ref.dstHandle.GetHandle(), copyRef);
235         }
236     }
237 }
238 
CopyImagesToImagesImpl(IRenderCommandList & cmdList,const vector<StagingCopyStruct> & imageToImage,const vector<ImageCopy> & imageCopies)239 void CopyImagesToImagesImpl(
240     IRenderCommandList& cmdList, const vector<StagingCopyStruct>& imageToImage, const vector<ImageCopy>& imageCopies)
241 {
242     for (const auto& ref : imageToImage) {
243         if (ref.invalidOperation) {
244             continue;
245         }
246         const uint32_t beginIndex = ref.beginIndex;
247         const uint32_t count = ref.count;
248         for (uint32_t idx = 0; idx < count; ++idx) {
249             const ImageCopy& copyRef = imageCopies[beginIndex + idx];
250             cmdList.CopyImageToImage(ref.srcHandle.GetHandle(), ref.dstHandle.GetHandle(), copyRef);
251         }
252     }
253 }
254 } // namespace
255 
Init(IRenderNodeContextManager & renderNodeContextMgr)256 void RenderStaging::Init(IRenderNodeContextManager& renderNodeContextMgr)
257 {
258     renderNodeContextMgr_ = &renderNodeContextMgr;
259 }
260 
PreExecuteFrame(const uint32_t clearByteSize)261 void RenderStaging::PreExecuteFrame(const uint32_t clearByteSize)
262 {
263     if (renderNodeContextMgr_->GetRenderNodeGraphData().renderingConfiguration.renderBackend ==
264         DeviceBackendType::OPENGLES) {
265         if (clearByteSize == 0) {
266             additionalCopyBuffer_ = {};
267         } else {
268             additionalCopyBuffer_.byteOffset = 0;
269             additionalCopyBuffer_.byteSize = clearByteSize;
270             const GpuBufferDesc desc {
271                 BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT, // usageFlags
272                 MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT |
273                     MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT, // memoryPropertyFlags
274                 0,                                                                 // engineCreationFlags
275                 additionalCopyBuffer_.byteSize,                                    // byteSize
276                 BASE_NS::Format::BASE_FORMAT_UNDEFINED,                            // format
277             };
278 
279             additionalCopyBuffer_.handle =
280                 renderNodeContextMgr_->GetGpuResourceManager().Create(additionalCopyBuffer_.handle, desc);
281         }
282     }
283 }
284 
CopyHostToStaging(const IRenderNodeGpuResourceManager & gpuResourceMgr,const StagingConsumeStruct & stagingData)285 void RenderStaging::CopyHostToStaging(
286     const IRenderNodeGpuResourceManager& gpuResourceMgr, const StagingConsumeStruct& stagingData)
287 {
288     auto const copyUserDataToStagingBuffer = [](auto& gpuResourceMgr, auto const& ref) {
289         auto* data = static_cast<uint8_t*>(gpuResourceMgr.MapBufferMemory(ref.srcHandle.GetHandle()));
290         if (!data) {
291             PLUGIN_LOG_E("staging: srcHandle %" PRIu64 " dstHandle %" PRIu64, ref.srcHandle.GetHandle().id,
292                 ref.dstHandle.GetHandle().id);
293             return;
294         }
295         auto const& bufferDesc = gpuResourceMgr.GetBufferDescriptor(ref.srcHandle.GetHandle());
296         const void* srcPtr = nullptr;
297         size_t srcSize = 0;
298         // should be removed already
299         PLUGIN_ASSERT(ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY);
300         if (ref.dataType == StagingCopyStruct::DataType::DATA_TYPE_VECTOR) {
301             srcPtr = ref.stagingData.data();
302             srcSize = ref.stagingData.size();
303         } else if (ref.dataType == StagingCopyStruct::DataType::DATA_TYPE_IMAGE_CONTAINER) {
304             PLUGIN_ASSERT(ref.imageContainerPtr);
305             if (ref.imageContainerPtr) {
306                 srcPtr = ref.imageContainerPtr->GetData().data();
307                 srcSize = ref.imageContainerPtr->GetData().size_bytes();
308             }
309         }
310         if ((srcPtr) && (srcSize > 0)) {
311             PLUGIN_ASSERT(bufferDesc.byteSize >= srcSize);
312             data += ref.stagingBufferByteOffset; // offset to staging buffer
313             if (!CloneData(data, bufferDesc.byteSize, srcPtr, srcSize)) {
314                 PLUGIN_LOG_E("Copying of staging data failed");
315             }
316         }
317         gpuResourceMgr.UnmapBuffer(ref.srcHandle.GetHandle());
318     };
319 
320     PLUGIN_ASSERT(!RenderHandleUtil::IsValid(stagingData.stagingBuffer));
321 
322     for (const auto& ref : stagingData.bufferToImage) {
323         if ((!ref.invalidOperation) && (ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY)) {
324             copyUserDataToStagingBuffer(gpuResourceMgr, ref);
325         }
326     }
327     for (const auto& ref : stagingData.bufferToBuffer) {
328         if ((!ref.invalidOperation) && (ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY)) {
329             copyUserDataToStagingBuffer(gpuResourceMgr, ref);
330         }
331     }
332 }
333 
CopyHostToStaging(const StagingConsumeStruct & stagingData,const StagingMappedBuffer & smb)334 void RenderStaging::CopyHostToStaging(const StagingConsumeStruct& stagingData, const StagingMappedBuffer& smb)
335 {
336     auto const copyUserDataToStagingBuffer = [](const auto& ref, const auto& smb) {
337         uint8_t* dataPtr = smb.mappedData;
338         if (!dataPtr) {
339 #if (RENDER_VALIDATION_ENABLED == 1)
340             PLUGIN_LOG_E("staging: srcHandle %" PRIu64 " dstHandle %" PRIu64, ref.srcHandle.GetHandle().id,
341                 ref.dstHandle.GetHandle().id);
342 #endif
343             return;
344         }
345         const void* srcPtr = nullptr;
346         size_t srcSize = 0;
347         // should be removed already
348         PLUGIN_ASSERT(ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY);
349         if (ref.dataType == StagingCopyStruct::DataType::DATA_TYPE_VECTOR) {
350             srcPtr = ref.stagingData.data();
351             srcSize = ref.stagingData.size();
352         } else if (ref.dataType == StagingCopyStruct::DataType::DATA_TYPE_IMAGE_CONTAINER) {
353             PLUGIN_ASSERT(ref.imageContainerPtr);
354             if (ref.imageContainerPtr) {
355                 srcPtr = ref.imageContainerPtr->GetData().data();
356                 srcSize = ref.imageContainerPtr->GetData().size_bytes();
357             }
358         }
359         if ((srcPtr) && (srcSize > 0)) {
360             const auto* dataEndPtr = smb.mappedData + smb.byteSize;
361             dataPtr = dataPtr + ref.stagingBufferByteOffset; // offset to staging buffer
362             if (!CloneData(dataPtr, size_t(dataEndPtr - dataPtr), srcPtr, srcSize)) {
363                 PLUGIN_LOG_E("Copying of staging data failed");
364             }
365         }
366     };
367 
368     for (const auto& ref : stagingData.bufferToImage) {
369         if ((!ref.invalidOperation) && (ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY)) {
370             copyUserDataToStagingBuffer(ref, smb);
371         }
372     }
373     for (const auto& ref : stagingData.bufferToBuffer) {
374         if ((!ref.invalidOperation) && (ref.dataType != StagingCopyStruct::DataType::DATA_TYPE_DIRECT_SRC_COPY)) {
375             copyUserDataToStagingBuffer(ref, smb);
376         }
377     }
378 }
379 
CopyStagingToImages(IRenderCommandList & cmdList,const IRenderNodeGpuResourceManager & gpuResourceMgr,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)380 void RenderStaging::CopyStagingToImages(IRenderCommandList& cmdList,
381     const IRenderNodeGpuResourceManager& gpuResourceMgr, const StagingConsumeStruct& stagingData,
382     const StagingConsumeStruct& renderDataStoreStagingData)
383 {
384     if (stagingData.bufferToImage.empty() && renderDataStoreStagingData.bufferToImage.empty()) {
385         return; // early out to prevent command list commands
386     }
387 
388     // explicit input barriers
389     cmdList.BeginDisableAutomaticBarrierPoints();
390     {
391         ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
392         const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
393             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
394             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
395         const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
396             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
397 
398         for (const auto& ref : stagingData.bufferToImage) {
399             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
400                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
401             }
402         }
403         for (const auto& ref : renderDataStoreStagingData.bufferToImage) {
404             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
405                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
406             }
407         }
408     }
409     cmdList.EndDisableAutomaticBarrierPoints();
410     cmdList.AddCustomBarrierPoint();
411 
412     CopyBuffersToImages(gpuResourceMgr, cmdList, stagingData.bufferToImage, stagingData.bufferImageCopies,
413         stagingData.scalingImageData);
414     CopyBuffersToImages(gpuResourceMgr, cmdList, renderDataStoreStagingData.bufferToImage,
415         renderDataStoreStagingData.bufferImageCopies, {}); // scaling from render data store not supported ATM
416 
417     // explicit output barriers
418     cmdList.BeginDisableAutomaticBarrierPoints();
419     {
420         const ImageResourceBarrier src {
421             AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT, PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
422             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL // we expect all mips to be transferred to dst
423         };
424         const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
425             PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
426             ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
427         const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
428             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
429 
430         for (const auto& ref : stagingData.bufferToImage) {
431             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
432                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
433             }
434         }
435         for (const auto& ref : renderDataStoreStagingData.bufferToImage) {
436             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
437                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
438             }
439         }
440     }
441     cmdList.EndDisableAutomaticBarrierPoints();
442     cmdList.AddCustomBarrierPoint();
443 }
444 
CopyImagesToBuffers(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)445 void RenderStaging::CopyImagesToBuffers(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
446     const StagingConsumeStruct& renderDataStoreStagingData)
447 {
448     if (renderDataStoreStagingData.imageToBuffer.empty()) {
449         return; // early out to prevent command list commands
450     }
451 
452     // explicit input barriers
453     cmdList.BeginDisableAutomaticBarrierPoints();
454     {
455         // we transfer all mip levels, but we only copy the one
456         ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
457         const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
458             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
459             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
460         const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
461             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
462 
463         for (const auto& ref : renderDataStoreStagingData.imageToBuffer) {
464             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
465                 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, dst, imageSubresourceRange);
466             }
467         }
468     }
469     cmdList.EndDisableAutomaticBarrierPoints();
470     cmdList.AddCustomBarrierPoint();
471 
472     // Not supported through gpu resource manager staging
473     PLUGIN_ASSERT(stagingData.imageToBuffer.empty());
474     CopyImagesToBuffersImpl(
475         cmdList, renderDataStoreStagingData.imageToBuffer, renderDataStoreStagingData.bufferImageCopies);
476 
477     // explicit output barriers
478     cmdList.BeginDisableAutomaticBarrierPoints();
479     {
480         const ImageResourceBarrier src {
481             AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT, PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
482             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // we expect all mips to be transferred to dst
483         };
484         // NOTE: should fetch usage flags
485         const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
486             PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
487             ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
488         const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
489             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
490 
491         for (const auto& ref : renderDataStoreStagingData.imageToBuffer) {
492             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
493                 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, dst, imageSubresourceRange);
494             }
495         }
496     }
497     cmdList.EndDisableAutomaticBarrierPoints();
498     cmdList.AddCustomBarrierPoint();
499 }
500 
CopyImagesToImages(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)501 void RenderStaging::CopyImagesToImages(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
502     const StagingConsumeStruct& renderDataStoreStagingData)
503 {
504     if (renderDataStoreStagingData.imageToImage.empty()) {
505         return; // early out to prevent command list commands
506     }
507 
508     // explicit input barriers
509     cmdList.BeginDisableAutomaticBarrierPoints();
510     {
511         // we transfer all mip levels, but we only copy the one
512         constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
513             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
514 
515         constexpr ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
516         constexpr ImageResourceBarrier srcDst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
517             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
518             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
519 
520         constexpr ImageResourceBarrier dstDst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
521             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
522             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
523 
524         for (const auto& ref : renderDataStoreStagingData.imageToImage) {
525             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
526                 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, srcDst, imageSubresourceRange);
527             }
528             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
529                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dstDst, imageSubresourceRange);
530             }
531         }
532     }
533     cmdList.EndDisableAutomaticBarrierPoints();
534     cmdList.AddCustomBarrierPoint();
535 
536     // Not supported through gpu resource manager staging
537     PLUGIN_ASSERT(stagingData.imageToImage.empty());
538     CopyImagesToImagesImpl(cmdList, renderDataStoreStagingData.imageToImage, renderDataStoreStagingData.imageCopies);
539 
540     // explicit output barriers
541     cmdList.BeginDisableAutomaticBarrierPoints();
542     {
543         constexpr ImageResourceBarrier srcSrc { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
544             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
545             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
546         constexpr ImageResourceBarrier dstSrc { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
547             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
548             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
549         // NOTE: should fetch usage flags
550         constexpr ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
551             PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
552             ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
553         constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
554             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
555 
556         for (const auto& ref : renderDataStoreStagingData.imageToImage) {
557             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
558                 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), srcSrc, dst, imageSubresourceRange);
559             }
560             if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
561                 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), dstSrc, dst, imageSubresourceRange);
562             }
563         }
564     }
565     cmdList.EndDisableAutomaticBarrierPoints();
566     cmdList.AddCustomBarrierPoint();
567 }
568 
CopyBuffersToBuffers(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)569 void RenderStaging::CopyBuffersToBuffers(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
570     const StagingConsumeStruct& renderDataStoreStagingData)
571 {
572     if (stagingData.bufferToBuffer.empty() && renderDataStoreStagingData.bufferToBuffer.empty()) {
573         return; // early out to prevent command list commands
574     }
575 
576     const auto copyBuffersToBuffers = [](IRenderCommandList& cmdList, const vector<StagingCopyStruct>& bufferToBuffer,
577                                           const vector<BufferCopy>& bufferCopies) {
578         for (const auto& ref : bufferToBuffer) {
579             if (ref.invalidOperation) {
580                 continue;
581             }
582             const auto copies = array_view(bufferCopies.data() + ref.beginIndex, ref.count);
583             for (const BufferCopy& copyRef : copies) {
584                 cmdList.CopyBufferToBuffer(ref.srcHandle.GetHandle(), ref.dstHandle.GetHandle(), copyRef);
585             }
586         }
587     };
588 
589     // dynamic resources can create barriers if needed
590     copyBuffersToBuffers(cmdList, stagingData.bufferToBuffer, stagingData.bufferCopies);
591     copyBuffersToBuffers(cmdList, renderDataStoreStagingData.bufferToBuffer, renderDataStoreStagingData.bufferCopies);
592 
593     // explict output barriers
594     cmdList.BeginDisableAutomaticBarrierPoints();
595     {
596         const BufferResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
597             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT };
598         const BufferResourceBarrier dst { 0, // access flags are not currently known
599             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
600 
601         for (const auto& ref : stagingData.bufferToBuffer) {
602             if (!ref.invalidOperation) {
603                 cmdList.CustomBufferBarrier(
604                     ref.dstHandle.GetHandle(), src, dst, 0, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE);
605             }
606         }
607         for (const auto& ref : renderDataStoreStagingData.bufferToBuffer) {
608             if (!ref.invalidOperation) {
609                 cmdList.CustomBufferBarrier(
610                     ref.dstHandle.GetHandle(), src, dst, 0, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE);
611             }
612         }
613     }
614     cmdList.EndDisableAutomaticBarrierPoints();
615     cmdList.AddCustomBarrierPoint();
616 }
617 
ClearImages(IRenderCommandList & cmdList,const IRenderNodeGpuResourceManager & gpuResourceMgr,const StagingImageClearConsumeStruct & imageClearData)618 void RenderStaging::ClearImages(IRenderCommandList& cmdList, const IRenderNodeGpuResourceManager& gpuResourceMgr,
619     const StagingImageClearConsumeStruct& imageClearData)
620 {
621     if (imageClearData.clears.empty()) {
622         return; // early out to prevent command list commands
623     }
624 
625     // explicit input barriers for resources that are not dynamic trackable
626     // NOTE: one probably only needs to clear dynamic trackable resources anyhow
627     cmdList.BeginDisableAutomaticBarrierPoints();
628     {
629         // we transfer all mip levels
630         constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
631             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
632 
633         constexpr ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
634             ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED };
635         constexpr ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
636             PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
637             ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
638 
639         for (const auto& ref : imageClearData.clears) {
640             if (!RenderHandleUtil::IsDynamicResource(ref.handle.GetHandle())) {
641                 cmdList.CustomImageBarrier(ref.handle.GetHandle(), src, dst, imageSubresourceRange);
642             }
643         }
644     }
645     cmdList.EndDisableAutomaticBarrierPoints();
646     cmdList.AddCustomBarrierPoint();
647 
648     // alternative path for GLES, ClearColorImage
649     if (renderNodeContextMgr_->GetRenderNodeGraphData().renderingConfiguration.renderBackend ==
650         DeviceBackendType::OPENGLES) {
651         if (additionalCopyBuffer_.handle && (!imageClearData.clears.empty())) {
652             if (auto dataPtr =
653                     reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(additionalCopyBuffer_.handle.GetHandle()));
654                 dataPtr) {
655                 for (const auto& ref : imageClearData.clears) {
656                     const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(ref.handle.GetHandle());
657                     const uint32_t bytesPerPixel =
658                         gpuResourceMgr.GetFormatProperties(ref.handle.GetHandle()).bytesPerPixel;
659                     const uint32_t imgByteSize = desc.width * desc.height * bytesPerPixel;
660                     ImageSubresourceLayers imageSubresourceLayers { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
661                         0, 1u };
662                     const BufferImageCopy bic {
663                         additionalCopyBuffer_.byteOffset, // bufferOffset
664                         0,                                // bufferRowLength
665                         0,                                // bufferImageHeight
666                         imageSubresourceLayers,           // imageSubresource
667                         { 0, 0, 0 },                      // imageOffset
668                         { desc.width, desc.height, 1u },  // imageExtent
669                     };
670 #if (RENDER_VALIDATION_ENABLED == 1)
671                     const bool hasDiffColorVals =
672                         ((ref.color.uint32[0] != ref.color.uint32[1]) || (ref.color.uint32[0] != ref.color.uint32[2]) ||
673                             (ref.color.uint32[0] != ref.color.uint32[3]));
674                     if ((bytesPerPixel > 4u) || hasDiffColorVals || (desc.depth > 1u)) {
675                         PLUGIN_LOG_ONCE_W("RenderStaging::ClearImages_gles",
676                             "RENDER_VALIDATION: only byte clears support with OpenGLES ClearColorImage");
677                     }
678 #endif
679                     if ((additionalCopyBuffer_.byteOffset + imgByteSize) <= additionalCopyBuffer_.byteSize) {
680                         ClearToValue(
681                             dataPtr, additionalCopyBuffer_.byteSize, uint8_t(0xff & ref.color.uint32[0]), imgByteSize);
682                         cmdList.CopyBufferToImage(
683                             additionalCopyBuffer_.handle.GetHandle(), ref.handle.GetHandle(), bic);
684                     }
685 
686                     // advance
687                     additionalCopyBuffer_.byteOffset += imgByteSize;
688                     dataPtr = dataPtr + additionalCopyBuffer_.byteOffset;
689                 }
690             }
691             gpuResourceMgr.UnmapBuffer(additionalCopyBuffer_.handle.GetHandle());
692         }
693     } else {
694         constexpr ImageSubresourceRange imgSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
695             PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
696         for (const auto& ref : imageClearData.clears) {
697             cmdList.ClearColorImage(ref.handle.GetHandle(), ref.color, { &imgSubresourceRange, 1 });
698         }
699         // NOTE: there's no way to guess the desired layout for non dynamic trackable clear resources
700     }
701 }
702 RENDER_END_NAMESPACE()
703