Commit 2ea15cd6 authored by Erik Faye-Lund 's avatar Erik Faye-Lund Committed by Marge Bot
Browse files

d3d12: introduce d3d12 gallium driver



This driver will allow running OpenGL and OpenCL on top of Gallium
for any hardware supporting Microsoft's Direct3D 12 on Windows 10.

This is the combination of a lot of commits from our development branch,
containing code from several authors.
Co-authored-by: Bill Kristiansen's avatarBill Kristiansen <billkris@microsoft.com>
Co-authored-by: Gert Wollny's avatarGert Wollny <gert.wollny@collabora.com>
Co-authored-by: Jesse Natalie's avatarJesse Natalie <jenatali@microsoft.com>
Co-authored-by: Louis-Francis Ratté-Boulianne's avatarLouis-Francis Ratté-Boulianne <lfrb@collabora.com>
Reviewed-By: Mike Blumenkrantz's avatarMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Acked-by: Jason Ekstrand's avatarJason Ekstrand <jason@jlekstrand.net>
Part-of: <mesa/mesa!7477>
parent 3f31cf64
......@@ -235,6 +235,7 @@ with_gallium_virgl = gallium_drivers.contains('virgl')
with_gallium_swr = gallium_drivers.contains('swr')
with_gallium_lima = gallium_drivers.contains('lima')
with_gallium_zink = gallium_drivers.contains('zink')
with_gallium_d3d12 = gallium_drivers.contains('d3d12')
with_gallium = gallium_drivers.length() != 0
......
......@@ -68,7 +68,7 @@ option(
choices : [
'auto', 'kmsro', 'radeonsi', 'r300', 'r600', 'nouveau', 'freedreno',
'swrast', 'v3d', 'vc4', 'etnaviv', 'tegra', 'i915', 'svga', 'virgl',
'swr', 'panfrost', 'iris', 'lima', 'zink'
'swr', 'panfrost', 'iris', 'lima', 'zink', 'd3d12'
],
description : 'List of gallium drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built'
)
......
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_batch.h"
#include "d3d12_context.h"
#include "d3d12_fence.h"
#include "d3d12_query.h"
#include "d3d12_resource.h"
#include "d3d12_screen.h"
#include "d3d12_surface.h"
#include "util/hash_table.h"
#include "util/set.h"
#include "util/u_inlines.h"
bool
d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
batch->bos = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
batch->sampler_views = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
batch->surfaces = _mesa_set_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
batch->objects = _mesa_set_create(NULL,
_mesa_hash_pointer,
_mesa_key_pointer_equal);
if (!batch->bos || !batch->sampler_views || !batch->surfaces || !batch->objects)
return false;
util_dynarray_init(&batch->zombie_samplers, NULL);
if (FAILED(screen->dev->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT,
__uuidof(batch->cmdalloc),
(void **)&batch->cmdalloc)))
return false;
batch->sampler_heap =
d3d12_descriptor_heap_new(screen->dev,
D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
128);
batch->view_heap =
d3d12_descriptor_heap_new(screen->dev,
D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
1024);
if (!batch->sampler_heap && !batch->view_heap)
return false;
return true;
}
static void
delete_bo(set_entry *entry)
{
struct d3d12_bo *bo = (struct d3d12_bo *)entry->key;
d3d12_bo_unreference(bo);
}
static void
delete_sampler_view(set_entry *entry)
{
struct pipe_sampler_view *pres = (struct pipe_sampler_view *)entry->key;
pipe_sampler_view_reference(&pres, NULL);
}
static void
delete_surface(set_entry *entry)
{
struct pipe_surface *surf = (struct pipe_surface *)entry->key;
pipe_surface_reference(&surf, NULL);
}
static void
delete_object(set_entry *entry)
{
ID3D12Object *object = (ID3D12Object *)entry->key;
object->Release();
}
bool
d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t timeout_ns)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
// batch hasn't been submitted before
if (!batch->fence && !batch->has_errors)
return true;
if (batch->fence) {
if (!d3d12_fence_finish(batch->fence, timeout_ns))
return false;
d3d12_fence_reference(&batch->fence, NULL);
}
_mesa_set_clear(batch->bos, delete_bo);
_mesa_set_clear(batch->sampler_views, delete_sampler_view);
_mesa_set_clear(batch->surfaces, delete_surface);
_mesa_set_clear(batch->objects, delete_object);
util_dynarray_foreach(&batch->zombie_samplers, d3d12_descriptor_handle, handle)
d3d12_descriptor_handle_free(handle);
util_dynarray_clear(&batch->zombie_samplers);
d3d12_descriptor_heap_clear(batch->view_heap);
d3d12_descriptor_heap_clear(batch->sampler_heap);
if (FAILED(batch->cmdalloc->Reset())) {
debug_printf("D3D12: resetting ID3D12CommandAllocator failed\n");
return false;
}
batch->has_errors = false;
return true;
}
void
d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);
batch->cmdalloc->Release();
d3d12_descriptor_heap_free(batch->sampler_heap);
d3d12_descriptor_heap_free(batch->view_heap);
_mesa_set_destroy(batch->bos, NULL);
_mesa_set_destroy(batch->sampler_views, NULL);
_mesa_set_destroy(batch->surfaces, NULL);
_mesa_set_destroy(batch->objects, NULL);
util_dynarray_fini(&batch->zombie_samplers);
}
void
d3d12_start_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
ID3D12DescriptorHeap* heaps[2] = { d3d12_descriptor_heap_get(batch->view_heap),
d3d12_descriptor_heap_get(batch->sampler_heap) };
d3d12_reset_batch(ctx, batch, PIPE_TIMEOUT_INFINITE);
/* Create or reset global command list */
if (ctx->cmdlist) {
if (FAILED(ctx->cmdlist->Reset(batch->cmdalloc, NULL))) {
debug_printf("D3D12: resetting ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
} else {
if (FAILED(screen->dev->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
batch->cmdalloc, NULL,
__uuidof(ctx->cmdlist),
(void **)&ctx->cmdlist))) {
debug_printf("D3D12: creating ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
}
ctx->cmdlist->SetDescriptorHeaps(2, heaps);
ctx->cmdlist_dirty = ~0;
for (int i = 0; i < D3D12_GFX_SHADER_STAGES; ++i)
ctx->shader_dirty[i] = ~0;
if (!ctx->queries_disabled)
d3d12_resume_queries(ctx);
}
void
d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch)
{
struct d3d12_screen *screen = d3d12_screen(ctx->base.screen);
if (!ctx->queries_disabled)
d3d12_suspend_queries(ctx);
if (FAILED(ctx->cmdlist->Close())) {
debug_printf("D3D12: closing ID3D12GraphicsCommandList failed\n");
batch->has_errors = true;
return;
}
ID3D12CommandList* cmdlists[] = { ctx->cmdlist };
screen->cmdqueue->ExecuteCommandLists(1, cmdlists);
batch->fence = d3d12_create_fence(screen, ctx);
}
bool
d3d12_batch_has_references(struct d3d12_batch *batch,
struct d3d12_bo *bo)
{
return (_mesa_set_search(batch->bos, bo) != NULL);
}
void
d3d12_batch_reference_resource(struct d3d12_batch *batch,
struct d3d12_resource *res)
{
if (!d3d12_batch_has_references(batch, res->bo)) {
_mesa_set_add(batch->bos, res->bo);
d3d12_bo_reference(res->bo);
}
}
void
d3d12_batch_reference_sampler_view(struct d3d12_batch *batch,
struct d3d12_sampler_view *sv)
{
struct set_entry *entry = _mesa_set_search(batch->sampler_views, sv);
if (!entry) {
entry = _mesa_set_add(batch->sampler_views, sv);
pipe_reference(NULL, &sv->base.reference);
}
}
void
d3d12_batch_reference_surface_texture(struct d3d12_batch *batch,
struct d3d12_surface *surf)
{
d3d12_batch_reference_resource(batch, d3d12_resource(surf->base.texture));
}
void
d3d12_batch_reference_object(struct d3d12_batch *batch,
ID3D12Object *object)
{
struct set_entry *entry = _mesa_set_search(batch->objects, object);
if (!entry) {
entry = _mesa_set_add(batch->objects, object);
object->AddRef();
}
}
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef D3D12_BATCH_H
#define D3D12_BATCH_H
#include "util/u_dynarray.h"
#include <stdint.h>
#define D3D12_IGNORE_SDK_LAYERS
#include <d3d12.h>
struct d3d12_bo;
struct d3d12_descriptor_heap;
struct d3d12_fence;
struct d3d12_batch {
struct d3d12_fence *fence;
struct set *bos;
struct set *sampler_views;
struct set *surfaces;
struct set *objects;
struct util_dynarray zombie_samplers;
ID3D12CommandAllocator *cmdalloc;
struct d3d12_descriptor_heap *sampler_heap;
struct d3d12_descriptor_heap *view_heap;
bool has_errors;
};
bool
d3d12_init_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_destroy_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_start_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
void
d3d12_end_batch(struct d3d12_context *ctx, struct d3d12_batch *batch);
bool
d3d12_reset_batch(struct d3d12_context *ctx, struct d3d12_batch *batch, uint64_t timeout_ns);
bool
d3d12_batch_has_references(struct d3d12_batch *batch,
struct d3d12_bo *bo);
void
d3d12_batch_reference_resource(struct d3d12_batch *batch,
struct d3d12_resource *res);
void
d3d12_batch_reference_sampler_view(struct d3d12_batch *batch,
struct d3d12_sampler_view *sv);
void
d3d12_batch_reference_surface_texture(struct d3d12_batch *batch,
struct d3d12_surface *surf);
void
d3d12_batch_reference_object(struct d3d12_batch *batch,
ID3D12Object *object);
#endif
/*
* Copyright © Microsoft Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "d3d12_context.h"
#include "d3d12_compiler.h"
#include "d3d12_debug.h"
#include "d3d12_format.h"
#include "d3d12_resource.h"
#include "d3d12_screen.h"
#include "util/u_blitter.h"
#include "util/format/u_format.h"
#include "nir_to_dxil.h"
#include "nir_builder.h"
static void
copy_buffer_region_no_barriers(struct d3d12_context *ctx,
struct d3d12_resource *dst,
uint64_t dst_offset,
struct d3d12_resource *src,
uint64_t src_offset,
uint64_t size)
{
uint64_t dst_off, src_off;
ID3D12Resource *dst_buf = d3d12_resource_underlying(dst, &dst_off);
ID3D12Resource *src_buf = d3d12_resource_underlying(src, &src_off);
ctx->cmdlist->CopyBufferRegion(dst_buf, dst_offset + dst_off,
src_buf, src_offset + src_off,
size);
}
static bool
is_resolve(const struct pipe_blit_info *info)
{
return info->src.resource->nr_samples > 1 &&
info->dst.resource->nr_samples <= 1;
}
static bool
resolve_supported(const struct pipe_blit_info *info)
{
assert(is_resolve(info));
// check for unsupported operations
if (util_format_is_depth_or_stencil(info->src.format) &&
info->mask != PIPE_MASK_Z) {
return false;
} else {
if (util_format_get_mask(info->dst.format) != info->mask ||
util_format_get_mask(info->src.format) != info->mask)
return false;
}
if (info->filter != PIPE_TEX_FILTER_NEAREST ||
info->scissor_enable ||
info->num_window_rectangles > 0 ||
info->alpha_blend)
return false;
// formats need to match
struct d3d12_resource *src = d3d12_resource(info->src.resource);
struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
if (src->dxgi_format != dst->dxgi_format)
return false;
if (util_format_is_pure_integer(src->base.format))
return false;
// sizes needs to match
if (info->src.box.width != info->dst.box.width ||
info->src.box.height != info->dst.box.height)
return false;
// can only resolve full subresource
if (info->src.box.width != u_minify(info->src.resource->width0,
info->src.level) ||
info->src.box.height != u_minify(info->src.resource->height0,
info->src.level) ||
info->dst.box.width != u_minify(info->dst.resource->width0,
info->dst.level) ||
info->dst.box.height != u_minify(info->dst.resource->height0,
info->dst.level))
return false;
return true;
}
static void
blit_resolve(struct d3d12_context *ctx, const struct pipe_blit_info *info)
{
struct d3d12_batch *batch = d3d12_current_batch(ctx);
struct d3d12_resource *src = d3d12_resource(info->src.resource);
struct d3d12_resource *dst = d3d12_resource(info->dst.resource);
d3d12_transition_resource_state(ctx, src,
D3D12_RESOURCE_STATE_RESOLVE_SOURCE);
d3d12_transition_resource_state(ctx, dst,
D3D12_RESOURCE_STATE_RESOLVE_DEST);
d3d12_apply_resource_states(ctx);
d3d12_batch_reference_resource(batch, src);
d3d12_batch_reference_resource(batch, dst);
DXGI_FORMAT dxgi_format = d3d12_get_resource_srv_format(src->base.format, src->base.target);
assert(src->dxgi_format == dst->dxgi_format);
ctx->cmdlist->ResolveSubresource(
d3d12_resource_resource(dst), info->dst.level,
d3d12_resource_resource(src), info->src.level,
dxgi_format);
}
static bool
formats_are_copy_compatible(enum pipe_format src, enum pipe_format dst)
{
if (src == dst)
return true;
/* We can skip the stencil copy */
if (util_format_get_depth_only(src) == dst ||
util_format_get_depth_only(dst) == src)
return true;
return false;
}
static bool
box_fits(const struct pipe_box *box, const struct pipe_resource *res, int level)
{
unsigned lwidth = u_minify(res->width0, level);
unsigned lheight= u_minify(res->height0, level);
unsigned ldepth = res->target == PIPE_TEXTURE_3D ? u_minify(res->depth0, level) :
res->array_size;
unsigned wb = box->x;
unsigned we = box->x + box->width;
unsigned hb = box->y;
unsigned he = box->y + box->height;
unsigned db = box->z;
unsigned de = box->z + box->depth;
return (wb <= lwidth && we <= lwidth &&
hb <= lheight && he <= lheight &&
db <= ldepth && de <= ldepth);
}
static bool
direct_copy_supported(struct d3d12_screen *screen,
const struct pipe_blit_info *info,
bool have_predication)
{
if (info->scissor_enable || info->alpha_blend ||
(have_predication && info->render_condition_enable) ||
MAX2(info->src.resource->nr_samples, 1) != MAX2(info->dst.resource->nr_samples, 1)) {
return false;
}
if (!formats_are_copy_compatible(info->src.format, info->dst.format))
return false;
if (util_format_is_depth_or_stencil(info->src.format) && !(info->mask & PIPE_MASK_ZS)) {
return false;
}
if (!util_format_is_depth_or_stencil(info->src.format)) {
if (util_format_get_mask(info->dst.format) != info->mask ||
util_format_get_mask(info->src.format) != info->mask)
return false;
}
if (abs(info->src.box.height) != info->dst.box.height) {
return false;
}
if (info->src.box.height != info->dst.box.height &&
(!util_format_is_depth_or_stencil(info->src.format) ||
screen->opts2.ProgrammableSamplePositionsTier ==
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED)) {
return false;
}
if (!box_fits(&info->dst.box, info->dst.resource, info->dst.level)) {
return false;
}
if (!box_fits(&info->src.box, info->src.resource, info->src.level)) {
return false;
}
if (info->src.box.width != info->dst.box.width) {
return false;
}
if (info->src.box.depth != info->dst.box.depth) {
return false;
}
if ((screen->opts2.ProgrammableSamplePositionsTier ==
D3D12_PROGRAMMABLE_SAMPLE_POSITIONS_TIER_NOT_SUPPORTED &&