1/* 2 * Copyright © Microsoft Corporation 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21 * IN THE SOFTWARE. 22 */ 23 24#include "d3d12_context.h" 25#include "d3d12_format.h" 26#include "d3d12_resource.h" 27#include "d3d12_screen.h" 28#include "d3d12_surface.h" 29 30#include "util/format/u_format.h" 31#include "util/u_inlines.h" 32#include "util/u_memory.h" 33 34static D3D12_DSV_DIMENSION 35view_dsv_dimension(enum pipe_texture_target target, unsigned samples) 36{ 37 switch (target) { 38 case PIPE_TEXTURE_1D: return D3D12_DSV_DIMENSION_TEXTURE1D; 39 case PIPE_TEXTURE_1D_ARRAY: return D3D12_DSV_DIMENSION_TEXTURE1DARRAY; 40 41 case PIPE_TEXTURE_2D: 42 case PIPE_TEXTURE_RECT: 43 return samples > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS : 44 D3D12_DSV_DIMENSION_TEXTURE2D; 45 46 case PIPE_TEXTURE_2D_ARRAY: 47 case PIPE_TEXTURE_CUBE: 48 case PIPE_TEXTURE_CUBE_ARRAY: 49 return samples > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY : 50 D3D12_DSV_DIMENSION_TEXTURE2DARRAY; 51 52 default: 53 unreachable("unexpected target"); 54 } 55} 56 57static D3D12_RTV_DIMENSION 58view_rtv_dimension(enum pipe_texture_target target, unsigned samples) 59{ 60 switch (target) { 61 case PIPE_BUFFER: return D3D12_RTV_DIMENSION_BUFFER; 62 case PIPE_TEXTURE_1D: return D3D12_RTV_DIMENSION_TEXTURE1D; 63 case PIPE_TEXTURE_1D_ARRAY: return D3D12_RTV_DIMENSION_TEXTURE1DARRAY; 64 65 case PIPE_TEXTURE_2D: 66 case PIPE_TEXTURE_RECT: 67 return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMS : 68 D3D12_RTV_DIMENSION_TEXTURE2D; 69 70 case PIPE_TEXTURE_2D_ARRAY: 71 case PIPE_TEXTURE_CUBE: 72 case PIPE_TEXTURE_CUBE_ARRAY: 73 return samples > 1 ? D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY : 74 D3D12_RTV_DIMENSION_TEXTURE2DARRAY; 75 76 case PIPE_TEXTURE_3D: return D3D12_RTV_DIMENSION_TEXTURE3D; 77 78 default: 79 unreachable("unexpected target"); 80 } 81} 82 83static void 84initialize_dsv(struct pipe_context *pctx, 85 struct pipe_resource *pres, 86 const struct pipe_surface *tpl, 87 struct d3d12_descriptor_handle *handle, 88 DXGI_FORMAT dxgi_format) 89{ 90 struct d3d12_resource *res = d3d12_resource(pres); 91 struct d3d12_screen *screen = d3d12_screen(pctx->screen); 92 93 D3D12_DEPTH_STENCIL_VIEW_DESC desc; 94 desc.Format = dxgi_format; 95 desc.Flags = D3D12_DSV_FLAG_NONE; 96 97 desc.ViewDimension = view_dsv_dimension(pres->target, pres->nr_samples); 98 switch (desc.ViewDimension) { 99 case D3D12_DSV_DIMENSION_TEXTURE1D: 100 if (tpl->u.tex.first_layer > 0) 101 debug_printf("D3D12: can't create 1D DSV from layer %d\n", 102 tpl->u.tex.first_layer); 103 104 desc.Texture1D.MipSlice = tpl->u.tex.level; 105 break; 106 107 case D3D12_DSV_DIMENSION_TEXTURE1DARRAY: 108 desc.Texture1DArray.MipSlice = tpl->u.tex.level; 109 desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer; 110 desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 111 break; 112 113 case D3D12_DSV_DIMENSION_TEXTURE2DMS: 114 if (tpl->u.tex.first_layer > 0) 115 debug_printf("D3D12: can't create 2DMS DSV from layer %d\n", 116 tpl->u.tex.first_layer); 117 118 break; 119 120 case D3D12_DSV_DIMENSION_TEXTURE2D: 121 if (tpl->u.tex.first_layer > 0) 122 debug_printf("D3D12: can't create 2D DSV from layer %d\n", 123 tpl->u.tex.first_layer); 124 125 desc.Texture2D.MipSlice = tpl->u.tex.level; 126 break; 127 128 case D3D12_DSV_DIMENSION_TEXTURE2DMSARRAY: 129 desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer; 130 desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 131 break; 132 133 case D3D12_DSV_DIMENSION_TEXTURE2DARRAY: 134 desc.Texture2DArray.MipSlice = tpl->u.tex.level; 135 desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer; 136 desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 137 break; 138 139 default: 140 unreachable("Unhandled DSV dimension"); 141 } 142 143 mtx_lock(&screen->descriptor_pool_mutex); 144 d3d12_descriptor_pool_alloc_handle(screen->dsv_pool, handle); 145 mtx_unlock(&screen->descriptor_pool_mutex); 146 147 screen->dev->CreateDepthStencilView(d3d12_resource_resource(res), &desc, 148 handle->cpu_handle); 149} 150 151static void 152initialize_rtv(struct pipe_context *pctx, 153 struct pipe_resource *pres, 154 const struct pipe_surface *tpl, 155 struct d3d12_descriptor_handle *handle, 156 DXGI_FORMAT dxgi_format) 157{ 158 struct d3d12_resource *res = d3d12_resource(pres); 159 struct d3d12_screen *screen = d3d12_screen(pctx->screen); 160 161 D3D12_RENDER_TARGET_VIEW_DESC desc; 162 desc.Format = dxgi_format; 163 164 desc.ViewDimension = view_rtv_dimension(pres->target, pres->nr_samples); 165 switch (desc.ViewDimension) { 166 case D3D12_RTV_DIMENSION_BUFFER: 167 desc.Buffer.FirstElement = 0; 168 desc.Buffer.NumElements = pres->width0 / util_format_get_blocksize(tpl->format); 169 break; 170 171 case D3D12_RTV_DIMENSION_TEXTURE1D: 172 if (tpl->u.tex.first_layer > 0) 173 debug_printf("D3D12: can't create 1D RTV from layer %d\n", 174 tpl->u.tex.first_layer); 175 176 desc.Texture1D.MipSlice = tpl->u.tex.level; 177 break; 178 179 case D3D12_RTV_DIMENSION_TEXTURE1DARRAY: 180 desc.Texture1DArray.MipSlice = tpl->u.tex.level; 181 desc.Texture1DArray.FirstArraySlice = tpl->u.tex.first_layer; 182 desc.Texture1DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 183 break; 184 185 case D3D12_RTV_DIMENSION_TEXTURE2DMS: 186 if (tpl->u.tex.first_layer > 0) 187 debug_printf("D3D12: can't create 2DMS RTV from layer %d\n", 188 tpl->u.tex.first_layer); 189 break; 190 191 case D3D12_RTV_DIMENSION_TEXTURE2D: 192 if (tpl->u.tex.first_layer > 0) 193 debug_printf("D3D12: can't create 2D RTV from layer %d\n", 194 tpl->u.tex.first_layer); 195 196 desc.Texture2D.MipSlice = tpl->u.tex.level; 197 desc.Texture2D.PlaneSlice = res->plane_slice; 198 break; 199 200 case D3D12_RTV_DIMENSION_TEXTURE2DMSARRAY: 201 desc.Texture2DMSArray.FirstArraySlice = tpl->u.tex.first_layer; 202 desc.Texture2DMSArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 203 break; 204 205 case D3D12_RTV_DIMENSION_TEXTURE2DARRAY: 206 desc.Texture2DArray.MipSlice = tpl->u.tex.level; 207 desc.Texture2DArray.FirstArraySlice = tpl->u.tex.first_layer; 208 desc.Texture2DArray.ArraySize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 209 desc.Texture2DArray.PlaneSlice = 0; 210 break; 211 212 case D3D12_RTV_DIMENSION_TEXTURE3D: 213 desc.Texture3D.MipSlice = tpl->u.tex.level; 214 desc.Texture3D.FirstWSlice = tpl->u.tex.first_layer; 215 desc.Texture3D.WSize = tpl->u.tex.last_layer - tpl->u.tex.first_layer + 1; 216 break; 217 218 default: 219 unreachable("Unhandled RTV dimension"); 220 } 221 222 mtx_lock(&screen->descriptor_pool_mutex); 223 d3d12_descriptor_pool_alloc_handle(screen->rtv_pool, handle); 224 mtx_unlock(&screen->descriptor_pool_mutex); 225 226 screen->dev->CreateRenderTargetView(d3d12_resource_resource(res), &desc, 227 handle->cpu_handle); 228} 229 230static struct pipe_surface * 231d3d12_create_surface(struct pipe_context *pctx, 232 struct pipe_resource *pres, 233 const struct pipe_surface *tpl) 234{ 235 bool is_depth_or_stencil = util_format_is_depth_or_stencil(tpl->format); 236 unsigned bind = is_depth_or_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET; 237 238 /* Don't bother if we don't support the requested format as RT or DS */ 239 if (!pctx->screen->is_format_supported(pctx->screen, tpl->format, PIPE_TEXTURE_2D, 240 tpl->nr_samples, tpl->nr_samples,bind)) 241 return NULL; 242 243 struct d3d12_surface *surface = CALLOC_STRUCT(d3d12_surface); 244 if (!surface) 245 return NULL; 246 247 pipe_resource_reference(&surface->base.texture, pres); 248 pipe_reference_init(&surface->base.reference, 1); 249 surface->base.context = pctx; 250 surface->base.format = tpl->format; 251 surface->base.width = u_minify(pres->width0, tpl->u.tex.level); 252 surface->base.height = u_minify(pres->height0, tpl->u.tex.level); 253 surface->base.u.tex.level = tpl->u.tex.level; 254 surface->base.u.tex.first_layer = tpl->u.tex.first_layer; 255 surface->base.u.tex.last_layer = tpl->u.tex.last_layer; 256 257 DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(tpl->format); 258 if (is_depth_or_stencil) 259 initialize_dsv(pctx, pres, tpl, &surface->desc_handle, dxgi_format); 260 else 261 initialize_rtv(pctx, pres, tpl, &surface->desc_handle, dxgi_format); 262 263 return &surface->base; 264} 265 266static void 267d3d12_surface_destroy(struct pipe_context *pctx, 268 struct pipe_surface *psurf) 269{ 270 struct d3d12_surface *surface = (struct d3d12_surface*) psurf; 271 struct d3d12_screen *screen = d3d12_screen(pctx->screen); 272 273 mtx_lock(&screen->descriptor_pool_mutex); 274 d3d12_descriptor_handle_free(&surface->desc_handle); 275 if (d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle)) 276 d3d12_descriptor_handle_free(&surface->uint_rtv_handle); 277 mtx_unlock(&screen->descriptor_pool_mutex); 278 279 pipe_resource_reference(&psurf->texture, NULL); 280 pipe_resource_reference(&surface->rgba_texture, NULL); 281 FREE(surface); 282} 283 284static void 285blit_surface(struct pipe_context *pctx, struct d3d12_surface *surface, bool pre) 286{ 287 struct pipe_blit_info info = {}; 288 289 info.src.resource = pre ? surface->base.texture : surface->rgba_texture; 290 info.dst.resource = pre ? surface->rgba_texture : surface->base.texture; 291 info.src.format = pre ? surface->base.texture->format : PIPE_FORMAT_R8G8B8A8_UNORM; 292 info.dst.format = pre ? PIPE_FORMAT_R8G8B8A8_UNORM : surface->base.texture->format; 293 info.src.level = info.dst.level = 0; 294 info.src.box.x = info.dst.box.x = 0; 295 info.src.box.y = info.dst.box.y = 0; 296 info.src.box.z = info.dst.box.z = 0; 297 info.src.box.width = info.dst.box.width = surface->base.width; 298 info.src.box.height = info.dst.box.height = surface->base.height; 299 info.src.box.depth = info.dst.box.depth = 0; 300 info.mask = PIPE_MASK_RGBA; 301 302 d3d12_blit(pctx, &info); 303} 304 305enum d3d12_surface_conversion_mode 306d3d12_surface_update_pre_draw(struct pipe_context *pctx, 307 struct d3d12_surface *surface, 308 DXGI_FORMAT format) 309{ 310 struct d3d12_screen *screen = d3d12_screen(surface->base.context->screen); 311 struct d3d12_resource *res = d3d12_resource(surface->base.texture); 312 DXGI_FORMAT dxgi_format = d3d12_get_resource_rt_format(surface->base.format); 313 enum d3d12_surface_conversion_mode mode; 314 315 if (dxgi_format == format) 316 return D3D12_SURFACE_CONVERSION_NONE; 317 318 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM || 319 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM) 320 mode = D3D12_SURFACE_CONVERSION_BGRA_UINT; 321 else 322 mode = D3D12_SURFACE_CONVERSION_RGBA_UINT; 323 324 if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT) { 325 if (!surface->rgba_texture) { 326 struct pipe_resource templ = {}; 327 struct pipe_resource *src = surface->base.texture; 328 329 templ.format = PIPE_FORMAT_R8G8B8A8_UNORM; 330 templ.width0 = src->width0; 331 templ.height0 = src->height0; 332 templ.depth0 = src->depth0; 333 templ.array_size = src->array_size; 334 templ.nr_samples = src->nr_samples; 335 templ.nr_storage_samples = src->nr_storage_samples; 336 templ.usage = PIPE_USAGE_DEFAULT | PIPE_USAGE_STAGING; 337 templ.bind = src->bind; 338 templ.target = src->target; 339 340 surface->rgba_texture = screen->base.resource_create(&screen->base, &templ); 341 } 342 343 blit_surface(pctx, surface, true); 344 res = d3d12_resource(surface->rgba_texture); 345 } 346 347 if (!d3d12_descriptor_handle_is_allocated(&surface->uint_rtv_handle)) { 348 initialize_rtv(surface->base.context, &res->base.b, &surface->base, 349 &surface->uint_rtv_handle, DXGI_FORMAT_R8G8B8A8_UINT); 350 } 351 352 return mode; 353} 354 355void 356d3d12_surface_update_post_draw(struct pipe_context *pctx, 357 struct d3d12_surface *surface, 358 enum d3d12_surface_conversion_mode mode) 359{ 360 if (mode == D3D12_SURFACE_CONVERSION_BGRA_UINT) 361 blit_surface(pctx, surface, false); 362} 363 364D3D12_CPU_DESCRIPTOR_HANDLE 365d3d12_surface_get_handle(struct d3d12_surface *surface, 366 enum d3d12_surface_conversion_mode mode) 367{ 368 if (mode != D3D12_SURFACE_CONVERSION_NONE) 369 return surface->uint_rtv_handle.cpu_handle; 370 return surface->desc_handle.cpu_handle; 371} 372 373void 374d3d12_context_surface_init(struct pipe_context *context) 375{ 376 context->create_surface = d3d12_create_surface; 377 context->surface_destroy = d3d12_surface_destroy; 378} 379