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