1 /*
2 * Copyright (c) 2024 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 // explicit input barriers
385 cmdList.BeginDisableAutomaticBarrierPoints();
386 {
387 ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
388 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
389 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
390 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
391 const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
392 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
393
394 for (const auto& ref : stagingData.bufferToImage) {
395 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
396 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
397 }
398 }
399 for (const auto& ref : renderDataStoreStagingData.bufferToImage) {
400 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
401 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
402 }
403 }
404 }
405 cmdList.EndDisableAutomaticBarrierPoints();
406 cmdList.AddCustomBarrierPoint();
407
408 CopyBuffersToImages(gpuResourceMgr, cmdList, stagingData.bufferToImage, stagingData.bufferImageCopies,
409 stagingData.scalingImageData);
410 CopyBuffersToImages(gpuResourceMgr, cmdList, renderDataStoreStagingData.bufferToImage,
411 renderDataStoreStagingData.bufferImageCopies, {}); // scaling from render data store not supported ATM
412
413 // explicit output barriers
414 cmdList.BeginDisableAutomaticBarrierPoints();
415 {
416 const ImageResourceBarrier src {
417 AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT, PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
418 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL // we expect all mips to be transferred to dst
419 };
420 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
421 PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
422 ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
423 const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
424 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
425
426 for (const auto& ref : stagingData.bufferToImage) {
427 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
428 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
429 }
430 }
431 for (const auto& ref : renderDataStoreStagingData.bufferToImage) {
432 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
433 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dst, imageSubresourceRange);
434 }
435 }
436 }
437 cmdList.EndDisableAutomaticBarrierPoints();
438 cmdList.AddCustomBarrierPoint();
439 }
440
CopyImagesToBuffers(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)441 void RenderStaging::CopyImagesToBuffers(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
442 const StagingConsumeStruct& renderDataStoreStagingData)
443 {
444 // explicit input barriers
445 cmdList.BeginDisableAutomaticBarrierPoints();
446 {
447 // we transfer all mip levels, but we only copy the one
448 ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
449 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
450 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
451 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
452 const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
453 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
454
455 for (const auto& ref : renderDataStoreStagingData.imageToBuffer) {
456 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
457 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, dst, imageSubresourceRange);
458 }
459 }
460 }
461 cmdList.EndDisableAutomaticBarrierPoints();
462 cmdList.AddCustomBarrierPoint();
463
464 // Not supported through gpu resource manager staging
465 PLUGIN_ASSERT(stagingData.imageToBuffer.empty());
466 CopyImagesToBuffersImpl(
467 cmdList, renderDataStoreStagingData.imageToBuffer, renderDataStoreStagingData.bufferImageCopies);
468
469 // explicit output barriers
470 cmdList.BeginDisableAutomaticBarrierPoints();
471 {
472 const ImageResourceBarrier src {
473 AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT, PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
474 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL // we expect all mips to be transferred to dst
475 };
476 // NOTE: should fetch usage flags
477 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
478 PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
479 ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
480 const ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
481 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
482
483 for (const auto& ref : renderDataStoreStagingData.imageToBuffer) {
484 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
485 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, dst, imageSubresourceRange);
486 }
487 }
488 }
489 cmdList.EndDisableAutomaticBarrierPoints();
490 cmdList.AddCustomBarrierPoint();
491 }
492
CopyImagesToImages(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)493 void RenderStaging::CopyImagesToImages(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
494 const StagingConsumeStruct& renderDataStoreStagingData)
495 {
496 // explicit input barriers
497 cmdList.BeginDisableAutomaticBarrierPoints();
498 {
499 // we transfer all mip levels, but we only copy the one
500 constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
501 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
502
503 constexpr ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT };
504 constexpr ImageResourceBarrier srcDst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
505 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
506 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
507
508 constexpr ImageResourceBarrier dstDst { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
509 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
510 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
511
512 for (const auto& ref : renderDataStoreStagingData.imageToImage) {
513 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
514 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), src, srcDst, imageSubresourceRange);
515 }
516 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
517 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), src, dstDst, imageSubresourceRange);
518 }
519 }
520 }
521 cmdList.EndDisableAutomaticBarrierPoints();
522 cmdList.AddCustomBarrierPoint();
523
524 // Not supported through gpu resource manager staging
525 PLUGIN_ASSERT(stagingData.imageToImage.empty());
526 CopyImagesToImagesImpl(cmdList, renderDataStoreStagingData.imageToImage, renderDataStoreStagingData.imageCopies);
527
528 // explicit output barriers
529 cmdList.BeginDisableAutomaticBarrierPoints();
530 {
531 constexpr ImageResourceBarrier srcSrc { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
532 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
533 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL };
534 constexpr ImageResourceBarrier dstSrc { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
535 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
536 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
537 // NOTE: should fetch usage flags
538 constexpr ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
539 PipelineStageFlagBits::CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // some shader stage
540 ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
541 constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
542 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
543
544 for (const auto& ref : renderDataStoreStagingData.imageToImage) {
545 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.srcHandle.GetHandle()))) {
546 cmdList.CustomImageBarrier(ref.srcHandle.GetHandle(), srcSrc, dst, imageSubresourceRange);
547 }
548 if ((!ref.invalidOperation) && (!RenderHandleUtil::IsDynamicResource(ref.dstHandle.GetHandle()))) {
549 cmdList.CustomImageBarrier(ref.dstHandle.GetHandle(), dstSrc, dst, imageSubresourceRange);
550 }
551 }
552 }
553 cmdList.EndDisableAutomaticBarrierPoints();
554 cmdList.AddCustomBarrierPoint();
555 }
556
CopyBuffersToBuffers(IRenderCommandList & cmdList,const StagingConsumeStruct & stagingData,const StagingConsumeStruct & renderDataStoreStagingData)557 void RenderStaging::CopyBuffersToBuffers(IRenderCommandList& cmdList, const StagingConsumeStruct& stagingData,
558 const StagingConsumeStruct& renderDataStoreStagingData)
559 {
560 const auto copyBuffersToBuffers = [](IRenderCommandList& cmdList, const vector<StagingCopyStruct>& bufferToBuffer,
561 const vector<BufferCopy>& bufferCopies) {
562 for (const auto& ref : bufferToBuffer) {
563 if (ref.invalidOperation) {
564 continue;
565 }
566 const auto copies = array_view(bufferCopies.data() + ref.beginIndex, ref.count);
567 for (const BufferCopy& copyRef : copies) {
568 cmdList.CopyBufferToBuffer(ref.srcHandle.GetHandle(), ref.dstHandle.GetHandle(), copyRef);
569 }
570 }
571 };
572
573 // dynamic resources can create barriers if needed
574 copyBuffersToBuffers(cmdList, stagingData.bufferToBuffer, stagingData.bufferCopies);
575 copyBuffersToBuffers(cmdList, renderDataStoreStagingData.bufferToBuffer, renderDataStoreStagingData.bufferCopies);
576
577 // explict output barriers
578 cmdList.BeginDisableAutomaticBarrierPoints();
579 {
580 const BufferResourceBarrier src { AccessFlagBits::CORE_ACCESS_TRANSFER_WRITE_BIT,
581 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT };
582 const BufferResourceBarrier dst { 0, // access flags are not currently known
583 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT };
584
585 for (const auto& ref : stagingData.bufferToBuffer) {
586 if (!ref.invalidOperation) {
587 cmdList.CustomBufferBarrier(
588 ref.dstHandle.GetHandle(), src, dst, 0, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE);
589 }
590 }
591 for (const auto& ref : renderDataStoreStagingData.bufferToBuffer) {
592 if (!ref.invalidOperation) {
593 cmdList.CustomBufferBarrier(
594 ref.dstHandle.GetHandle(), src, dst, 0, PipelineStateConstants::GPU_BUFFER_WHOLE_SIZE);
595 }
596 }
597 }
598 cmdList.EndDisableAutomaticBarrierPoints();
599 cmdList.AddCustomBarrierPoint();
600 }
601
ClearImages(IRenderCommandList & cmdList,const IRenderNodeGpuResourceManager & gpuResourceMgr,const StagingImageClearConsumeStruct & imageClearData)602 void RenderStaging::ClearImages(IRenderCommandList& cmdList, const IRenderNodeGpuResourceManager& gpuResourceMgr,
603 const StagingImageClearConsumeStruct& imageClearData)
604 {
605 // explicit input barriers for resources that are not dynamic trackable
606 // NOTE: one probably only needs to clear dynamic trackable resources anyhow
607 cmdList.BeginDisableAutomaticBarrierPoints();
608 {
609 // we transfer all mip levels
610 constexpr ImageSubresourceRange imageSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
611 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
612
613 constexpr ImageResourceBarrier src { 0, PipelineStageFlagBits::CORE_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
614 ImageLayout::CORE_IMAGE_LAYOUT_UNDEFINED };
615 constexpr ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_TRANSFER_READ_BIT,
616 PipelineStageFlagBits::CORE_PIPELINE_STAGE_TRANSFER_BIT,
617 ImageLayout::CORE_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL };
618
619 for (const auto& ref : imageClearData.clears) {
620 if (!RenderHandleUtil::IsDynamicResource(ref.handle.GetHandle())) {
621 cmdList.CustomImageBarrier(ref.handle.GetHandle(), src, dst, imageSubresourceRange);
622 }
623 }
624 }
625 cmdList.EndDisableAutomaticBarrierPoints();
626 cmdList.AddCustomBarrierPoint();
627
628 // alternative path for GLES, ClearColorImage
629 if (renderNodeContextMgr_->GetRenderNodeGraphData().renderingConfiguration.renderBackend ==
630 DeviceBackendType::OPENGLES) {
631 if (additionalCopyBuffer_.handle && (!imageClearData.clears.empty())) {
632 if (auto dataPtr =
633 reinterpret_cast<uint8_t*>(gpuResourceMgr.MapBuffer(additionalCopyBuffer_.handle.GetHandle()));
634 dataPtr) {
635 for (const auto& ref : imageClearData.clears) {
636 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(ref.handle.GetHandle());
637 const uint32_t bytesPerPixel =
638 gpuResourceMgr.GetFormatProperties(ref.handle.GetHandle()).bytesPerPixel;
639 const uint32_t imgByteSize = desc.width * desc.height * bytesPerPixel;
640 ImageSubresourceLayers imageSubresourceLayers { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
641 0, 1u };
642 const BufferImageCopy bic {
643 additionalCopyBuffer_.byteOffset, // bufferOffset
644 0, // bufferRowLength
645 0, // bufferImageHeight
646 imageSubresourceLayers, // imageSubresource
647 { 0, 0, 0 }, // imageOffset
648 { desc.width, desc.height, 1u }, // imageExtent
649 };
650 #if (RENDER_VALIDATION_ENABLED == 1)
651 const bool hasDiffColorVals =
652 ((ref.color.uint32[0] != ref.color.uint32[1]) || (ref.color.uint32[0] != ref.color.uint32[2]) ||
653 (ref.color.uint32[0] != ref.color.uint32[3]));
654 if ((bytesPerPixel > 4u) || hasDiffColorVals || (desc.depth > 1u)) {
655 PLUGIN_LOG_ONCE_W("RenderStaging::ClearImages_gles",
656 "RENDER_VALIDATION: only byte clears support with OpenGLES ClearColorImage");
657 }
658 #endif
659 if ((additionalCopyBuffer_.byteOffset + imgByteSize) <= additionalCopyBuffer_.byteSize) {
660 ClearToValue(
661 dataPtr, additionalCopyBuffer_.byteSize, uint8_t(0xff & ref.color.uint32[0]), imgByteSize);
662 cmdList.CopyBufferToImage(
663 additionalCopyBuffer_.handle.GetHandle(), ref.handle.GetHandle(), bic);
664 }
665
666 // advance
667 additionalCopyBuffer_.byteOffset += imgByteSize;
668 dataPtr = dataPtr + additionalCopyBuffer_.byteOffset;
669 }
670 }
671 gpuResourceMgr.UnmapBuffer(additionalCopyBuffer_.handle.GetHandle());
672 }
673 } else {
674 constexpr ImageSubresourceRange imgSubresourceRange { ImageAspectFlagBits::CORE_IMAGE_ASPECT_COLOR_BIT, 0,
675 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
676 for (const auto& ref : imageClearData.clears) {
677 cmdList.ClearColorImage(ref.handle.GetHandle(), ref.color, { &imgSubresourceRange, 1 });
678 }
679 // NOTE: there's no way to guess the desired layout for non dynamic trackable clear resources
680 }
681 }
682 RENDER_END_NAMESPACE()
683