@@ -235,7 +235,7 @@ namespace HAL::API
235235 if (!rtv || !rtv->Resource ) return ;
236236
237237 auto & api = static_cast <API ::Resource&>(*rtv->Resource );
238- VkImageView view = api.get_import_handle (). image_view ;
238+ VkImageView view = api.get_vk_image_view () ;
239239 if (view == VK_NULL_HANDLE ) return ;
240240
241241 end_rendering_if_active ();
@@ -280,7 +280,7 @@ namespace HAL::API
280280 if (!dv || !dv->Resource ) return ;
281281
282282 auto & api = static_cast <API ::Resource&>(*dv->Resource );
283- VkImageView view = api.get_import_handle (). image_view ;
283+ VkImageView view = api.get_vk_image_view () ;
284284 if (view == VK_NULL_HANDLE ) return ;
285285
286286 end_rendering_if_active ();
@@ -311,7 +311,33 @@ namespace HAL::API
311311 if (d) clear_depth (dsv, fd);
312312 }
313313 void CommandList::clear_stencil (const DSVHandle& dsv, UINT8 ) {}
314- void CommandList::clear_uav (const UAVHandle&, vec4) {}
314+ void CommandList::clear_uav (const UAVHandle& h, vec4 color)
315+ {
316+ if (vk_cmd == VK_NULL_HANDLE || !h.is_valid ()) return ;
317+
318+ auto & ri = h.get_resource_info ();
319+ auto * uav = std::get_if<Views::UnorderedAccess>(&ri.view );
320+ if (!uav || !uav->Resource ) return ;
321+
322+ auto & api = static_cast <API ::Resource&>(*uav->Resource );
323+ VkImage img = api.get_vk_image ();
324+ if (img == VK_NULL_HANDLE ) return ;
325+
326+ end_rendering_if_active ();
327+
328+ VkClearColorValue cv{};
329+ cv.float32 [0 ] = color.x ;
330+ cv.float32 [1 ] = color.y ;
331+ cv.float32 [2 ] = color.z ;
332+ cv.float32 [3 ] = color.w ;
333+
334+ // UAV/storage images live in GENERAL layout (the HAL transitions to
335+ // UNORDERED_ACCESS before this call).
336+ VkImageSubresourceRange range{ VK_IMAGE_ASPECT_COLOR_BIT ,
337+ 0 , VK_REMAINING_MIP_LEVELS ,
338+ 0 , VK_REMAINING_ARRAY_LAYERS };
339+ vkCmdClearColorImage (vk_cmd, img, VK_IMAGE_LAYOUT_GENERAL , &cv, 1 , &range);
340+ }
315341
316342 // ---- Lazy render-pass start (for draw calls) ----------------------------
317343
@@ -594,21 +620,67 @@ namespace HAL::API
594620 dst_api.get_vk_buffer (), 1 , ®ion);
595621 }
596622
623+ // Build a VkBufferImageCopy from the HAL texture_layout. The staging buffer
624+ // rows are 256-byte aligned (see Device::get_texture_layout), so bufferRowLength
625+ // must be expressed in texels = row_stride / bytes-per-texel (NOT 0, which would
626+ // assume tight packing and shear the image for non-aligned widths).
627+ static VkBufferImageCopy make_buffer_image_copy (const HAL ::Resource& resource,
628+ ivec3 offset, ivec3 box, UINT sub_resource,
629+ const ResourceAddress& address,
630+ const texture_layout& layout)
631+ {
632+ if (box.y == 0 ) box.y = 1 ;
633+ if (box.z == 0 ) box.z = 1 ;
634+
635+ auto sinfo = layout.format .surface_info ({ (uint)box.x , (uint)box.y });
636+ uint bpt = box.x ? (uint)(sinfo.rowBytes / box.x ) : 4u ; // bytes per texel
637+ if (bpt == 0 ) bpt = 4u ;
638+
639+ auto & tdesc = resource.get_desc ().as_texture ();
640+ uint mips = tdesc.MipLevels ? tdesc.MipLevels : 1u ;
641+
642+ VkBufferImageCopy region{};
643+ region.bufferOffset = address.resource_offset ;
644+ region.bufferRowLength = (layout.row_stride / bpt);
645+ region.bufferImageHeight = 0 ; // tight vertically: rows = imageExtent.height
646+ region.imageSubresource = { VK_IMAGE_ASPECT_COLOR_BIT ,
647+ sub_resource % mips, sub_resource / mips, 1 };
648+ region.imageOffset = { offset.x , offset.y , offset.z };
649+ region.imageExtent = { (uint32_t )box.x , (uint32_t )box.y , (uint32_t )box.z };
650+ return region;
651+ }
652+
597653 void CommandList::update_texture (HAL ::Resource* resource, ivec3 offset, ivec3 box,
598654 UINT sub_resource, ResourceAddress address,
599655 texture_layout layout)
600656 {
601- if (!resource || vk_cmd == VK_NULL_HANDLE ) return ;
657+ if (!resource || vk_cmd == VK_NULL_HANDLE || !address. resource ) return ;
602658 auto & dst = static_cast <API ::Resource&>(*resource);
603- if (dst.get_vk_image () == VK_NULL_HANDLE ) return ;
659+ auto & staging = static_cast <API ::Resource&>(*address.resource );
660+ if (dst.get_vk_image () == VK_NULL_HANDLE || staging.get_vk_buffer () == VK_NULL_HANDLE )
661+ return ;
604662
605- // `address` is a GPU address to a staging buffer; we need the VkBuffer.
606- // Phase 5: look up staging buffer from the address.
607- // For now this is a stub — real implementation needs the staging buffer handle.
663+ // The HAL transitions `resource` to COPY_DEST (→ TRANSFER_DST_OPTIMAL) before this call.
664+ VkBufferImageCopy region = make_buffer_image_copy (*resource, offset, box, sub_resource, address, layout);
665+ vkCmdCopyBufferToImage (vk_cmd, staging.get_vk_buffer (), dst.get_vk_image (),
666+ VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL , 1 , ®ion);
608667 }
609668
610- void CommandList::read_texture (const HAL ::Resource*, ivec3, ivec3, UINT ,
611- ResourceAddress, texture_layout) {}
669+ void CommandList::read_texture (const HAL ::Resource* resource, ivec3 offset, ivec3 box,
670+ UINT sub_resource, ResourceAddress target,
671+ texture_layout layout)
672+ {
673+ if (!resource || vk_cmd == VK_NULL_HANDLE || !target.resource ) return ;
674+ auto & src = static_cast <const API ::Resource&>(*resource);
675+ auto & staging = static_cast <API ::Resource&>(*target.resource );
676+ if (src.get_vk_image () == VK_NULL_HANDLE || staging.get_vk_buffer () == VK_NULL_HANDLE )
677+ return ;
678+
679+ // The HAL transitions `resource` to COPY_SOURCE (→ TRANSFER_SRC_OPTIMAL) before this call.
680+ VkBufferImageCopy region = make_buffer_image_copy (*resource, offset, box, sub_resource, target, layout);
681+ vkCmdCopyImageToBuffer (vk_cmd, src.get_vk_image (),
682+ VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL , staging.get_vk_buffer (), 1 , ®ion);
683+ }
612684
613685 void CommandList::copy_texture (const Resource::ptr& dest, int dest_sub,
614686 const Resource::ptr& source, int src_sub)
0 commit comments