@@ -59,9 +59,13 @@ static void d3d12_heap_destroy(struct d3d12_heap *heap)
5959{
6060 TRACE ("Destroying heap %p.\n" , heap );
6161
62+ #ifdef VKD3D_ENABLE_DESCRIPTOR_QA
63+ vkd3d_free (heap -> placements );
64+ pthread_mutex_destroy (& heap -> placement_lock );
65+ #endif
66+
6267 vkd3d_free_memory (heap -> device , & heap -> device -> memory_allocator , & heap -> allocation );
6368 vkd3d_private_store_destroy (& heap -> private_store );
64- d3d12_device_release (heap -> device );
6569 vkd3d_free (heap );
6670}
6771
@@ -72,6 +76,18 @@ static void d3d12_heap_set_name(struct d3d12_heap *heap, const char *name)
7276 VK_OBJECT_TYPE_DEVICE_MEMORY , name );
7377}
7478
79+ void d3d12_heap_dec_ref (struct d3d12_heap * heap )
80+ {
81+ ULONG refcount = InterlockedDecrement (& heap -> internal_refcount );
82+ if (!refcount )
83+ d3d12_heap_destroy (heap );
84+ }
85+
86+ void d3d12_heap_inc_ref (struct d3d12_heap * heap )
87+ {
88+ InterlockedIncrement (& heap -> internal_refcount );
89+ }
90+
7591static ULONG STDMETHODCALLTYPE d3d12_heap_Release (d3d12_heap_iface * iface )
7692{
7793 struct d3d12_heap * heap = impl_from_ID3D12Heap1 (iface );
@@ -80,7 +96,11 @@ static ULONG STDMETHODCALLTYPE d3d12_heap_Release(d3d12_heap_iface *iface)
8096 TRACE ("%p decreasing refcount to %u.\n" , heap , refcount );
8197
8298 if (!refcount )
83- d3d12_heap_destroy (heap );
99+ {
100+ struct d3d12_device * device = heap -> device ;
101+ d3d12_heap_dec_ref (heap );
102+ d3d12_device_release (device );
103+ }
84104
85105 return refcount ;
86106}
@@ -216,6 +236,117 @@ static HRESULT validate_heap_desc(struct d3d12_device *device, const D3D12_HEAP_
216236 return S_OK ;
217237}
218238
239+ #ifdef VKD3D_ENABLE_DESCRIPTOR_QA
240+ static bool d3d12_resource_is_linear_placement (const struct d3d12_resource * resource )
241+ {
242+ return (resource -> desc .Dimension == D3D12_RESOURCE_DIMENSION_BUFFER &&
243+ !(resource -> flags & VKD3D_RESOURCE_ACCELERATION_STRUCTURE )) ||
244+ (resource -> flags & VKD3D_RESOURCE_LINEAR_TILING );
245+ }
246+
247+ static void d3d12_resource_report_parameters (char * buf , size_t buf_size , const struct d3d12_resource * resource )
248+ {
249+ if (resource -> desc .Dimension != D3D12_RESOURCE_DIMENSION_BUFFER )
250+ {
251+ snprintf (buf , buf_size ,
252+ "IMAGE: format = %s, width = %" PRIu64 ", height = %u, depth/layers = %u, levels = %u, flags = #%x" ,
253+ debug_dxgi_format (resource -> desc .Format ),
254+ resource -> desc .Width ,
255+ resource -> desc .Height ,
256+ resource -> desc .DepthOrArraySize ,
257+ resource -> desc .MipLevels ,
258+ resource -> desc .Flags );
259+ }
260+ else if (resource -> flags & VKD3D_RESOURCE_ACCELERATION_STRUCTURE )
261+ snprintf (buf , buf_size , "RTAS" );
262+ else
263+ snprintf (buf , buf_size , "BUFFER" );
264+ }
265+
266+ void d3d12_heap_register_placed_resource (struct d3d12_heap * heap ,
267+ struct d3d12_resource * resource ,
268+ VkDeviceSize heap_offset , VkDeviceSize required_size )
269+ {
270+ const struct d3d12_heap_resource_placement * placement ;
271+ bool candidate_resource_is_linear ;
272+ bool placed_resource_is_linear ;
273+ VkDeviceSize begin_overlap ;
274+ VkDeviceSize end_overlap ;
275+ char report_buffer [1024 ];
276+ bool has_alias = false;
277+ const char * msg ;
278+ size_t i ;
279+
280+ /* Linear aliasing with other linear resources is fine.
281+ * Image <-> Image, and Image <-> Buffer is far more dangerous however. */
282+ placed_resource_is_linear = d3d12_resource_is_linear_placement (resource );
283+
284+ pthread_mutex_lock (& heap -> placement_lock );
285+
286+ for (i = 0 ; i < heap -> placements_count ; i ++ )
287+ {
288+ placement = & heap -> placements [i ];
289+ candidate_resource_is_linear = d3d12_resource_is_linear_placement (placement -> resource );
290+
291+ begin_overlap = max (placement -> heap_offset , heap_offset );
292+ end_overlap = min (placement -> heap_offset + placement -> size , heap_offset + required_size );
293+
294+ if (begin_overlap < end_overlap && candidate_resource_is_linear != placed_resource_is_linear )
295+ {
296+ /* Overlap. */
297+ /* Potentially problematic scenario, report this. */
298+ if (!has_alias )
299+ {
300+ if (resource -> desc .Dimension == D3D12_RESOURCE_DIMENSION_BUFFER )
301+ msg = "Attempting to place linear buffer resource on heap, placement aliases with non-linear layout." ;
302+ else
303+ msg = "Attempting to place opaque resource on heap, placement aliases with other resources." ;
304+
305+ d3d12_resource_report_parameters (report_buffer , sizeof (report_buffer ), resource );
306+ INFO ("\n%s\n New placement: resource cookie = %" PRIu64 ", offset = %" PRIu64 ", size = %" PRIu64 ", VA = %" PRIx64 "\n\t%s\n" ,
307+ msg ,
308+ resource -> res .cookie ,
309+ heap_offset , required_size , resource -> res .va ,
310+ report_buffer );
311+
312+ has_alias = true;
313+ }
314+
315+ d3d12_resource_report_parameters (report_buffer , sizeof (report_buffer ), placement -> resource );
316+ INFO ("\n Existing aliasing resource : cookie = %" PRIu64 ", offset = %" PRIu64 ", size = %" PRIu64 ".\n\t\t%s\n" ,
317+ placement -> resource -> res .cookie , placement -> heap_offset , placement -> size ,
318+ report_buffer );
319+ }
320+ }
321+
322+ vkd3d_array_reserve ((void * * )& heap -> placements , & heap -> placements_size ,
323+ heap -> placements_count + 1 , sizeof (* heap -> placements ));
324+
325+ heap -> placements [heap -> placements_count ].resource = resource ;
326+ heap -> placements [heap -> placements_count ].heap_offset = heap_offset ;
327+ heap -> placements [heap -> placements_count ].size = required_size ;
328+ heap -> placements_count ++ ;
329+
330+ pthread_mutex_unlock (& heap -> placement_lock );
331+ }
332+
333+ void d3d12_heap_unregister_placed_resource (struct d3d12_heap * heap , struct d3d12_resource * resource )
334+ {
335+ size_t i ;
336+
337+ pthread_mutex_lock (& heap -> placement_lock );
338+ for (i = 0 ; i < heap -> placements_count ; i ++ )
339+ {
340+ if (heap -> placements [i ].resource == resource )
341+ {
342+ heap -> placements [i ] = heap -> placements [-- heap -> placements_count ];
343+ break ;
344+ }
345+ }
346+ pthread_mutex_unlock (& heap -> placement_lock );
347+ }
348+ #endif
349+
219350static HRESULT d3d12_heap_init (struct d3d12_heap * heap , struct d3d12_device * device ,
220351 const D3D12_HEAP_DESC * desc , void * host_address )
221352{
@@ -225,6 +356,7 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, struct d3d12_device *dev
225356 memset (heap , 0 , sizeof (* heap ));
226357 heap -> ID3D12Heap_iface .lpVtbl = & d3d12_heap_vtbl ;
227358 heap -> refcount = 1 ;
359+ heap -> internal_refcount = 1 ;
228360 heap -> desc = * desc ;
229361 heap -> device = device ;
230362
@@ -252,6 +384,10 @@ static HRESULT d3d12_heap_init(struct d3d12_heap *heap, struct d3d12_device *dev
252384 return hr ;
253385 }
254386
387+ #ifdef VKD3D_ENABLE_DESCRIPTOR_QA
388+ pthread_mutex_init (& heap -> placement_lock , NULL );
389+ #endif
390+
255391 d3d12_device_add_ref (heap -> device );
256392 return S_OK ;
257393}
0 commit comments