radv: add initial non-conformant radv vulkan driver

This squashes all the radv development up until now into
one for merging.

History can be found:
https://github.com/airlied/mesa/tree/semi-interesting

This requires llvm 3.9 and is in no way considered
a conformant vulkan implementation. It can run a number
of vulkan applications, and supports all GPUs using
the amdgpu kernel driver.

Thanks to Intel for providing anv and spirv->nir,
and Emil Velikov for reviewing build integration.

Parts of this are:
Reviewed-by: Nicolai Hähnle <nicolai.haehnle@amd.com>
Acked-by: Edward O'Callaghan <funfunctor@folklore1984.net>

Authors: Bas Nieuwenhuizen and Dave Airlie
Signed-off-by: Dave Airlie <airlied@redhat.com>
This commit is contained in:
Dave Airlie 2016-10-07 09:16:09 +10:00
parent 28ecd3eac2
commit f4e499ec79
63 changed files with 32093 additions and 8 deletions

View File

@ -1715,6 +1715,10 @@ if test -n "$with_vulkan_drivers"; then
HAVE_INTEL_VULKAN=yes;
;;
xradeon)
PKG_CHECK_MODULES([AMDGPU], [libdrm_amdgpu >= $LIBDRM_AMDGPU_REQUIRED])
HAVE_RADEON_VULKAN=yes;
;;
*)
AC_MSG_ERROR([Vulkan driver '$driver' does not exist])
;;
@ -2198,7 +2202,7 @@ if test "x$enable_gallium_llvm" = xauto; then
i*86|x86_64|amd64) enable_gallium_llvm=yes;;
esac
fi
if test "x$enable_gallium_llvm" = xyes; then
if test "x$enable_gallium_llvm" = xyes || test "x$HAVE_RADEON_VULKAN" = xyes; then
if test -n "$llvm_prefix"; then
AC_PATH_TOOL([LLVM_CONFIG], [llvm-config], [no], ["$llvm_prefix/bin"])
else
@ -2368,10 +2372,7 @@ radeon_llvm_check() {
else
amdgpu_llvm_target_name='amdgpu'
fi
if test "x$enable_gallium_llvm" != "xyes"; then
AC_MSG_ERROR([--enable-gallium-llvm is required when building $1])
fi
llvm_check_version_for "3" "6" "0" $1
llvm_check_version_for $2 $3 $4 $1
if test true && $LLVM_CONFIG --targets-built | grep -iqvw $amdgpu_llvm_target_name ; then
AC_MSG_ERROR([LLVM $amdgpu_llvm_target_name not enabled in your LLVM build.])
fi
@ -2382,6 +2383,13 @@ radeon_llvm_check() {
fi
}
radeon_gallium_llvm_check() {
if test "x$enable_gallium_llvm" != "xyes"; then
AC_MSG_ERROR([--enable-gallium-llvm is required when building $1])
fi
radeon_llvm_check $*
}
swr_llvm_check() {
gallium_require_llvm $1
if test ${LLVM_VERSION_INT} -lt 306; then
@ -2466,7 +2474,7 @@ if test -n "$with_gallium_drivers"; then
gallium_require_drm "Gallium R600"
gallium_require_drm_loader
if test "x$enable_opencl" = xyes; then
radeon_llvm_check "r600g"
radeon_gallium_llvm_check "r600g" "3" "6" "0"
LLVM_COMPONENTS="${LLVM_COMPONENTS} bitreader asmparser"
fi
;;
@ -2476,7 +2484,7 @@ if test -n "$with_gallium_drivers"; then
PKG_CHECK_MODULES([AMDGPU], [libdrm_amdgpu >= $LIBDRM_AMDGPU_REQUIRED])
gallium_require_drm "radeonsi"
gallium_require_drm_loader
radeon_llvm_check "radeonsi"
radeon_gallium_llvm_check "radeonsi" "3" "6" "0"
require_egl_drm "radeonsi"
;;
xnouveau)
@ -2541,6 +2549,10 @@ if test -n "$with_gallium_drivers"; then
done
fi
if test "x$HAVE_RADEON_VULKAN" != "x0"; then
radeon_llvm_check "radv" "3" "9" "0"
fi
dnl Set LLVM_LIBS - This is done after the driver configuration so
dnl that drivers can add additional components to LLVM_COMPONENTS.
dnl Previously, gallium drivers were updating LLVM_LIBS directly
@ -2632,8 +2644,13 @@ AM_CONDITIONAL(HAVE_R200_DRI, test x$HAVE_R200_DRI = xyes)
AM_CONDITIONAL(HAVE_RADEON_DRI, test x$HAVE_RADEON_DRI = xyes)
AM_CONDITIONAL(HAVE_SWRAST_DRI, test x$HAVE_SWRAST_DRI = xyes)
AM_CONDITIONAL(HAVE_RADEON_VULKAN, test "x$HAVE_RADEON_VULKAN" = xyes)
AM_CONDITIONAL(HAVE_INTEL_VULKAN, test "x$HAVE_INTEL_VULKAN" = xyes)
AM_CONDITIONAL(HAVE_AMD_DRIVERS, test "x$HAVE_GALLIUM_R600" = xyes -o \
"x$HAVE_GALLIUM_RADEONSI" = xyes -o \
"x$HAVE_RADEON_VULKAN" = xyes)
AM_CONDITIONAL(HAVE_INTEL_DRIVERS, test "x$HAVE_INTEL_VULKAN" = xyes -o \
"x$HAVE_I965_DRI" = xyes)
@ -2726,6 +2743,8 @@ dnl Substitute the config
AC_CONFIG_FILES([Makefile
src/Makefile
src/amd/Makefile
src/amd/common/Makefile
src/amd/vulkan/Makefile
src/compiler/Makefile
src/egl/Makefile
src/egl/main/egl.pc

View File

@ -74,7 +74,7 @@ endif
# include only conditionally ?
SUBDIRS += compiler
if HAVE_GALLIUM_RADEON_COMMON
if HAVE_AMD_DRIVERS
SUBDIRS += amd
endif
@ -120,6 +120,12 @@ if HAVE_INTEL_VULKAN
SUBDIRS += intel/vulkan
endif
# Requires wayland-drm
if HAVE_RADEON_VULKAN
SUBDIRS += amd/common
SUBDIRS += amd/vulkan
endif
if HAVE_GALLIUM
SUBDIRS += gallium
endif

View File

@ -0,0 +1,51 @@
# Copyright © 2016 Bas Nieuwenhuizen
#
# 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 Makefile.sources
# TODO cleanup these
AM_CPPFLAGS = \
$(VALGRIND_CFLAGS) \
$(DEFINES) \
-I$(top_srcdir)/include \
-I$(top_builddir)/src \
-I$(top_srcdir)/src \
-I$(top_builddir)/src/compiler \
-I$(top_builddir)/src/compiler/nir \
-I$(top_srcdir)/src/compiler \
-I$(top_srcdir)/src/mapi \
-I$(top_srcdir)/src/mesa \
-I$(top_srcdir)/src/mesa/drivers/dri/common \
-I$(top_srcdir)/src/gallium/auxiliary \
-I$(top_srcdir)/src/gallium/include
AM_CFLAGS = $(VISIBILITY_CFLAGS) \
$(PTHREAD_CFLAGS) \
$(LLVM_CFLAGS) \
$(LIBELF_CFLAGS)
AM_CXXFLAGS = \
$(VISIBILITY_CXXFLAGS) \
$(LLVM_CXXFLAGS)
noinst_LTLIBRARIES = libamd_common.la
libamd_common_la_SOURCES = $(AMD_COMPILER_SOURCES)

View File

@ -0,0 +1,29 @@
# Copyright © 2016 Bas Nieuwenhuizen
#
# 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.
AMD_COMPILER_SOURCES := \
ac_binary.c \
ac_binary.h \
ac_llvm_helper.cpp \
ac_llvm_util.c \
ac_llvm_util.h \
ac_nir_to_llvm.c \
ac_nir_to_llvm.h

288
src/amd/common/ac_binary.c Normal file
View File

@ -0,0 +1,288 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* 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.
*
* Authors: Tom Stellard <thomas.stellard@amd.com>
*
* Based on radeon_elf_util.c.
*/
#include "ac_binary.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#include <gelf.h>
#include <libelf.h>
#include <stdio.h>
#include <sid.h>
#define SPILLED_SGPRS 0x4
#define SPILLED_VGPRS 0x8
static void parse_symbol_table(Elf_Data *symbol_table_data,
const GElf_Shdr *symbol_table_header,
struct ac_shader_binary *binary)
{
GElf_Sym symbol;
unsigned i = 0;
unsigned symbol_count =
symbol_table_header->sh_size / symbol_table_header->sh_entsize;
/* We are over allocating this list, because symbol_count gives the
* total number of symbols, and we will only be filling the list
* with offsets of global symbols. The memory savings from
* allocating the correct size of this list will be small, and
* I don't think it is worth the cost of pre-computing the number
* of global symbols.
*/
binary->global_symbol_offsets = CALLOC(symbol_count, sizeof(uint64_t));
while (gelf_getsym(symbol_table_data, i++, &symbol)) {
unsigned i;
if (GELF_ST_BIND(symbol.st_info) != STB_GLOBAL ||
symbol.st_shndx == 0 /* Undefined symbol */) {
continue;
}
binary->global_symbol_offsets[binary->global_symbol_count] =
symbol.st_value;
/* Sort the list using bubble sort. This list will usually
* be small. */
for (i = binary->global_symbol_count; i > 0; --i) {
uint64_t lhs = binary->global_symbol_offsets[i - 1];
uint64_t rhs = binary->global_symbol_offsets[i];
if (lhs < rhs) {
break;
}
binary->global_symbol_offsets[i] = lhs;
binary->global_symbol_offsets[i - 1] = rhs;
}
++binary->global_symbol_count;
}
}
static void parse_relocs(Elf *elf, Elf_Data *relocs, Elf_Data *symbols,
unsigned symbol_sh_link,
struct ac_shader_binary *binary)
{
unsigned i;
if (!relocs || !symbols || !binary->reloc_count) {
return;
}
binary->relocs = CALLOC(binary->reloc_count,
sizeof(struct ac_shader_reloc));
for (i = 0; i < binary->reloc_count; i++) {
GElf_Sym symbol;
GElf_Rel rel;
char *symbol_name;
struct ac_shader_reloc *reloc = &binary->relocs[i];
gelf_getrel(relocs, i, &rel);
gelf_getsym(symbols, GELF_R_SYM(rel.r_info), &symbol);
symbol_name = elf_strptr(elf, symbol_sh_link, symbol.st_name);
reloc->offset = rel.r_offset;
strncpy(reloc->name, symbol_name, sizeof(reloc->name)-1);
reloc->name[sizeof(reloc->name)-1] = 0;
}
}
void ac_elf_read(const char *elf_data, unsigned elf_size,
struct ac_shader_binary *binary)
{
char *elf_buffer;
Elf *elf;
Elf_Scn *section = NULL;
Elf_Data *symbols = NULL, *relocs = NULL;
size_t section_str_index;
unsigned symbol_sh_link = 0;
/* One of the libelf implementations
* (http://www.mr511.de/software/english.htm) requires calling
* elf_version() before elf_memory().
*/
elf_version(EV_CURRENT);
elf_buffer = MALLOC(elf_size);
memcpy(elf_buffer, elf_data, elf_size);
elf = elf_memory(elf_buffer, elf_size);
elf_getshdrstrndx(elf, &section_str_index);
while ((section = elf_nextscn(elf, section))) {
const char *name;
Elf_Data *section_data = NULL;
GElf_Shdr section_header;
if (gelf_getshdr(section, &section_header) != &section_header) {
fprintf(stderr, "Failed to read ELF section header\n");
return;
}
name = elf_strptr(elf, section_str_index, section_header.sh_name);
if (!strcmp(name, ".text")) {
section_data = elf_getdata(section, section_data);
binary->code_size = section_data->d_size;
binary->code = MALLOC(binary->code_size * sizeof(unsigned char));
memcpy(binary->code, section_data->d_buf, binary->code_size);
} else if (!strcmp(name, ".AMDGPU.config")) {
section_data = elf_getdata(section, section_data);
binary->config_size = section_data->d_size;
binary->config = MALLOC(binary->config_size * sizeof(unsigned char));
memcpy(binary->config, section_data->d_buf, binary->config_size);
} else if (!strcmp(name, ".AMDGPU.disasm")) {
/* Always read disassembly if it's available. */
section_data = elf_getdata(section, section_data);
binary->disasm_string = strndup(section_data->d_buf,
section_data->d_size);
} else if (!strncmp(name, ".rodata", 7)) {
section_data = elf_getdata(section, section_data);
binary->rodata_size = section_data->d_size;
binary->rodata = MALLOC(binary->rodata_size * sizeof(unsigned char));
memcpy(binary->rodata, section_data->d_buf, binary->rodata_size);
} else if (!strncmp(name, ".symtab", 7)) {
symbols = elf_getdata(section, section_data);
symbol_sh_link = section_header.sh_link;
parse_symbol_table(symbols, &section_header, binary);
} else if (!strcmp(name, ".rel.text")) {
relocs = elf_getdata(section, section_data);
binary->reloc_count = section_header.sh_size /
section_header.sh_entsize;
}
}
parse_relocs(elf, relocs, symbols, symbol_sh_link, binary);
if (elf){
elf_end(elf);
}
FREE(elf_buffer);
/* Cache the config size per symbol */
if (binary->global_symbol_count) {
binary->config_size_per_symbol =
binary->config_size / binary->global_symbol_count;
} else {
binary->global_symbol_count = 1;
binary->config_size_per_symbol = binary->config_size;
}
}
static
const unsigned char *ac_shader_binary_config_start(
const struct ac_shader_binary *binary,
uint64_t symbol_offset)
{
unsigned i;
for (i = 0; i < binary->global_symbol_count; ++i) {
if (binary->global_symbol_offsets[i] == symbol_offset) {
unsigned offset = i * binary->config_size_per_symbol;
return binary->config + offset;
}
}
return binary->config;
}
static const char *scratch_rsrc_dword0_symbol =
"SCRATCH_RSRC_DWORD0";
static const char *scratch_rsrc_dword1_symbol =
"SCRATCH_RSRC_DWORD1";
void ac_shader_binary_read_config(struct ac_shader_binary *binary,
struct ac_shader_config *conf,
unsigned symbol_offset)
{
unsigned i;
const unsigned char *config =
ac_shader_binary_config_start(binary, symbol_offset);
bool really_needs_scratch = false;
/* LLVM adds SGPR spills to the scratch size.
* Find out if we really need the scratch buffer.
*/
for (i = 0; i < binary->reloc_count; i++) {
const struct ac_shader_reloc *reloc = &binary->relocs[i];
if (!strcmp(scratch_rsrc_dword0_symbol, reloc->name) ||
!strcmp(scratch_rsrc_dword1_symbol, reloc->name)) {
really_needs_scratch = true;
break;
}
}
for (i = 0; i < binary->config_size_per_symbol; i+= 8) {
unsigned reg = util_le32_to_cpu(*(uint32_t*)(config + i));
unsigned value = util_le32_to_cpu(*(uint32_t*)(config + i + 4));
switch (reg) {
case R_00B028_SPI_SHADER_PGM_RSRC1_PS:
case R_00B128_SPI_SHADER_PGM_RSRC1_VS:
case R_00B228_SPI_SHADER_PGM_RSRC1_GS:
case R_00B848_COMPUTE_PGM_RSRC1:
conf->num_sgprs = MAX2(conf->num_sgprs, (G_00B028_SGPRS(value) + 1) * 8);
conf->num_vgprs = MAX2(conf->num_vgprs, (G_00B028_VGPRS(value) + 1) * 4);
conf->float_mode = G_00B028_FLOAT_MODE(value);
break;
case R_00B02C_SPI_SHADER_PGM_RSRC2_PS:
conf->lds_size = MAX2(conf->lds_size, G_00B02C_EXTRA_LDS_SIZE(value));
break;
case R_00B84C_COMPUTE_PGM_RSRC2:
conf->lds_size = MAX2(conf->lds_size, G_00B84C_LDS_SIZE(value));
break;
case R_0286CC_SPI_PS_INPUT_ENA:
conf->spi_ps_input_ena = value;
break;
case R_0286D0_SPI_PS_INPUT_ADDR:
conf->spi_ps_input_addr = value;
break;
case R_0286E8_SPI_TMPRING_SIZE:
case R_00B860_COMPUTE_TMPRING_SIZE:
/* WAVESIZE is in units of 256 dwords. */
if (really_needs_scratch)
conf->scratch_bytes_per_wave =
G_00B860_WAVESIZE(value) * 256 * 4;
break;
case SPILLED_SGPRS:
conf->spilled_sgprs = value;
break;
case SPILLED_VGPRS:
conf->spilled_vgprs = value;
break;
default:
{
static bool printed;
if (!printed) {
fprintf(stderr, "Warning: LLVM emitted unknown "
"config register: 0x%x\n", reg);
printed = true;
}
}
break;
}
if (!conf->spi_ps_input_addr)
conf->spi_ps_input_addr = conf->spi_ps_input_ena;
}
}

View File

@ -0,0 +1,88 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* 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.
*
* Authors: Tom Stellard <thomas.stellard@amd.com>
*
*/
#pragma once
#include <stdint.h>
struct ac_shader_reloc {
char name[32];
uint64_t offset;
};
struct ac_shader_binary {
/** Shader code */
unsigned char *code;
unsigned code_size;
/** Config/Context register state that accompanies this shader.
* This is a stream of dword pairs. First dword contains the
* register address, the second dword contains the value.*/
unsigned char *config;
unsigned config_size;
/** The number of bytes of config information for each global symbol.
*/
unsigned config_size_per_symbol;
/** Constant data accessed by the shader. This will be uploaded
* into a constant buffer. */
unsigned char *rodata;
unsigned rodata_size;
/** List of symbol offsets for the shader */
uint64_t *global_symbol_offsets;
unsigned global_symbol_count;
struct ac_shader_reloc *relocs;
unsigned reloc_count;
/** Disassembled shader in a string. */
char *disasm_string;
};
struct ac_shader_config {
unsigned num_sgprs;
unsigned num_vgprs;
unsigned spilled_sgprs;
unsigned spilled_vgprs;
unsigned lds_size;
unsigned spi_ps_input_ena;
unsigned spi_ps_input_addr;
unsigned float_mode;
unsigned scratch_bytes_per_wave;
};
/*
* Parse the elf binary stored in \p elf_data and create a
* ac_shader_binary object.
*/
void ac_elf_read(const char *elf_data, unsigned elf_size,
struct ac_shader_binary *binary);
void ac_shader_binary_read_config(struct ac_shader_binary *binary,
struct ac_shader_config *conf,
unsigned symbol_offset);

View File

@ -0,0 +1,46 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/* based on Marek's patch to lp_bld_misc.cpp */
// Workaround http://llvm.org/PR23628
#if HAVE_LLVM >= 0x0307
# pragma push_macro("DEBUG")
# undef DEBUG
#endif
#include "ac_nir_to_llvm.h"
#include <llvm-c/Core.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
extern "C" void
ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes)
{
llvm::Argument *A = llvm::unwrap<llvm::Argument>(val);
llvm::AttrBuilder B;
B.addDereferenceableAttr(bytes);
A->addAttr(llvm::AttributeSet::get(A->getContext(), A->getArgNo() + 1, B));
}

View File

@ -0,0 +1,142 @@
/*
* Copyright 2014 Advanced Micro Devices, Inc.
*
* 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
/* based on pieces from si_pipe.c and radeon_llvm_emit.c */
#include "ac_llvm_util.h"
#include <llvm-c/Core.h>
#include "c11/threads.h"
#include <assert.h>
#include <stdio.h>
static void ac_init_llvm_target()
{
#if HAVE_LLVM < 0x0307
LLVMInitializeR600TargetInfo();
LLVMInitializeR600Target();
LLVMInitializeR600TargetMC();
LLVMInitializeR600AsmPrinter();
#else
LLVMInitializeAMDGPUTargetInfo();
LLVMInitializeAMDGPUTarget();
LLVMInitializeAMDGPUTargetMC();
LLVMInitializeAMDGPUAsmPrinter();
#endif
}
static once_flag ac_init_llvm_target_once_flag = ONCE_FLAG_INIT;
static LLVMTargetRef ac_get_llvm_target(const char *triple)
{
LLVMTargetRef target = NULL;
char *err_message = NULL;
call_once(&ac_init_llvm_target_once_flag, ac_init_llvm_target);
if (LLVMGetTargetFromTriple(triple, &target, &err_message)) {
fprintf(stderr, "Cannot find target for triple %s ", triple);
if (err_message) {
fprintf(stderr, "%s\n", err_message);
}
LLVMDisposeMessage(err_message);
return NULL;
}
return target;
}
static const char *ac_get_llvm_processor_name(enum radeon_family family)
{
switch (family) {
case CHIP_TAHITI:
return "tahiti";
case CHIP_PITCAIRN:
return "pitcairn";
case CHIP_VERDE:
return "verde";
case CHIP_OLAND:
return "oland";
case CHIP_HAINAN:
return "hainan";
case CHIP_BONAIRE:
return "bonaire";
case CHIP_KABINI:
return "kabini";
case CHIP_KAVERI:
return "kaveri";
case CHIP_HAWAII:
return "hawaii";
case CHIP_MULLINS:
return "mullins";
case CHIP_TONGA:
return "tonga";
case CHIP_ICELAND:
return "iceland";
case CHIP_CARRIZO:
return "carrizo";
#if HAVE_LLVM <= 0x0307
case CHIP_FIJI:
return "tonga";
case CHIP_STONEY:
return "carrizo";
#else
case CHIP_FIJI:
return "fiji";
case CHIP_STONEY:
return "stoney";
#endif
#if HAVE_LLVM <= 0x0308
case CHIP_POLARIS10:
return "tonga";
case CHIP_POLARIS11:
return "tonga";
#else
case CHIP_POLARIS10:
return "polaris10";
case CHIP_POLARIS11:
return "polaris11";
#endif
default:
return "";
}
}
LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family)
{
assert(family >= CHIP_TAHITI);
const char *triple = "amdgcn--";
LLVMTargetRef target = ac_get_llvm_target(triple);
LLVMTargetMachineRef tm = LLVMCreateTargetMachine(
target,
triple,
ac_get_llvm_processor_name(family),
"+DumpCode,+vgpr-spilling",
LLVMCodeGenLevelDefault,
LLVMRelocDefault,
LLVMCodeModelDefault);
return tm;
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2016 Bas Nieuwenhuizen
*
* 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
*/
#pragma once
#include <llvm-c/TargetMachine.h>
#include "amd_family.h"
LLVMTargetMachineRef ac_create_target_machine(enum radeon_family family);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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.
*/
#pragma once
#include <stdbool.h>
#include "llvm-c/Core.h"
#include "llvm-c/TargetMachine.h"
#include "amd_family.h"
struct ac_shader_binary;
struct ac_shader_config;
struct nir_shader;
struct radv_pipeline_layout;
struct ac_vs_variant_key {
uint32_t instance_rate_inputs;
};
struct ac_fs_variant_key {
uint32_t col_format;
uint32_t is_int8;
};
union ac_shader_variant_key {
struct ac_vs_variant_key vs;
struct ac_fs_variant_key fs;
};
struct ac_nir_compiler_options {
struct radv_pipeline_layout *layout;
union ac_shader_variant_key key;
bool unsafe_math;
enum radeon_family family;
enum chip_class chip_class;
};
struct ac_shader_variant_info {
unsigned num_user_sgprs;
unsigned num_input_sgprs;
unsigned num_input_vgprs;
union {
struct {
unsigned param_exports;
unsigned pos_exports;
unsigned vgpr_comp_cnt;
uint32_t export_mask;
bool writes_pointsize;
uint8_t clip_dist_mask;
uint8_t cull_dist_mask;
} vs;
struct {
unsigned num_interp;
uint32_t input_mask;
unsigned output_mask;
uint32_t flat_shaded_mask;
bool has_pcoord;
bool can_discard;
bool writes_z;
bool writes_stencil;
bool early_fragment_test;
bool writes_memory;
} fs;
struct {
unsigned block_size[3];
} cs;
};
};
void ac_compile_nir_shader(LLVMTargetMachineRef tm,
struct ac_shader_binary *binary,
struct ac_shader_config *config,
struct ac_shader_variant_info *shader_info,
struct nir_shader *nir,
const struct ac_nir_compiler_options *options,
bool dump_shader);
#ifdef __cplusplus
extern "C"
#endif
void ac_add_attr_dereferenceable(LLVMValueRef val, uint64_t bytes);

6
src/amd/vulkan/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
# Generated source files
/radv_entrypoints.c
/radv_entrypoints.h
/radv_timestamp.h
/dev_icd.json
/vk_format_table.c

165
src/amd/vulkan/Makefile.am Normal file
View File

@ -0,0 +1,165 @@
# Copyright © 2016 Red Hat
#
# 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 Makefile.sources
vulkan_includedir = $(includedir)/vulkan
vulkan_include_HEADERS = \
$(top_srcdir)/include/vulkan/vk_platform.h \
$(top_srcdir)/include/vulkan/vulkan.h
lib_LTLIBRARIES = libvulkan_radeon.la
# The gallium includes are for the util/u_math.h include from main/macros.h
AM_CPPFLAGS = \
$(AMDGPU_CFLAGS) \
$(VALGRIND_CFLAGS) \
$(DEFINES) \
-I$(top_srcdir)/include \
-I$(top_builddir)/src \
-I$(top_srcdir)/src \
-I$(top_srcdir)/src/amd \
-I$(top_srcdir)/src/amd/common \
-I$(top_builddir)/src/compiler \
-I$(top_builddir)/src/compiler/nir \
-I$(top_srcdir)/src/compiler \
-I$(top_srcdir)/src/mapi \
-I$(top_srcdir)/src/mesa \
-I$(top_srcdir)/src/mesa/drivers/dri/common \
-I$(top_srcdir)/src/gallium/auxiliary \
-I$(top_srcdir)/src/gallium/include
AM_CFLAGS = $(VISIBILITY_FLAGS) \
$(PTHREAD_CFLAGS) \
$(LLVM_CFLAGS)
VULKAN_SOURCES = \
$(VULKAN_GENERATED_FILES) \
$(VULKAN_FILES)
VULKAN_LIB_DEPS = $(AMDGPU_LIBS)
if HAVE_PLATFORM_X11
AM_CPPFLAGS += \
$(XCB_DRI3_CFLAGS) \
-DVK_USE_PLATFORM_XCB_KHR \
-DVK_USE_PLATFORM_XLIB_KHR
VULKAN_SOURCES += $(VULKAN_WSI_X11_FILES)
# FIXME: Use pkg-config for X11-xcb ldflags.
VULKAN_LIB_DEPS += $(XCB_DRI3_LIBS) -lX11-xcb
endif
if HAVE_PLATFORM_WAYLAND
AM_CPPFLAGS += \
-I$(top_builddir)/src/egl/wayland/wayland-drm \
-I$(top_srcdir)/src/egl/wayland/wayland-drm \
$(WAYLAND_CFLAGS) \
-DVK_USE_PLATFORM_WAYLAND_KHR
VULKAN_SOURCES += $(VULKAN_WSI_WAYLAND_FILES)
VULKAN_LIB_DEPS += \
$(top_builddir)/src/egl/wayland/wayland-drm/libwayland-drm.la \
$(WAYLAND_LIBS)
endif
noinst_LTLIBRARIES = libvulkan_common.la
libvulkan_common_la_SOURCES = $(VULKAN_SOURCES)
VULKAN_LIB_DEPS += \
libvulkan_common.la \
$(top_builddir)/src/amd/common/libamd_common.la \
$(top_builddir)/src/compiler/nir/libnir.la \
$(top_builddir)/src/util/libmesautil.la \
$(LLVM_LIBS) \
$(LIBELF_LIBS) \
$(PTHREAD_LIBS) \
$(LIBDRM_LIBS) \
$(PTHREAD_LIBS) \
$(DLOPEN_LIBS) \
-lm
nodist_EXTRA_libvulkan_radeon_la_SOURCES = dummy.cpp
libvulkan_radeon_la_SOURCES = $(VULKAN_GEM_FILES)
radv_entrypoints.h : radv_entrypoints_gen.py $(vulkan_include_HEADERS)
$(AM_V_GEN) cat $(vulkan_include_HEADERS) |\
$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py header > $@
radv_entrypoints.c : radv_entrypoints_gen.py $(vulkan_include_HEADERS)
$(AM_V_GEN) cat $(vulkan_include_HEADERS) |\
$(PYTHON2) $(srcdir)/radv_entrypoints_gen.py code > $@
.PHONY: radv_timestamp.h
radv_timestamp.h:
@echo "Updating radv_timestamp.h"
$(AM_V_GEN) echo "#define RADV_TIMESTAMP \"$(TIMESTAMP_CMD)\"" > $@
vk_format_table.c: vk_format_table.py \
vk_format_parse.py \
vk_format_layout.csv
$(PYTHON2) $(srcdir)/vk_format_table.py $(srcdir)/vk_format_layout.csv > $@
BUILT_SOURCES = $(VULKAN_GENERATED_FILES)
CLEANFILES = $(BUILT_SOURCES) dev_icd.json radv_timestamp.h
EXTRA_DIST = \
$(top_srcdir)/include/vulkan/vk_icd.h \
radv_entrypoints_gen.py \
dev_icd.json.in \
radeon_icd.json
libvulkan_radeon_la_LIBADD = $(VULKAN_LIB_DEPS) $(top_builddir)/src/amd/addrlib/libamdgpu_addrlib.la
libvulkan_radeon_la_LDFLAGS = \
-shared \
-module \
-no-undefined \
-avoid-version \
$(BSYMBOLIC) \
$(LLVM_LDFLAGS) \
$(GC_SECTIONS) \
$(LD_NO_UNDEFINED)
icdconfdir = @VULKAN_ICD_INSTALL_DIR@
icdconf_DATA = radeon_icd.json
# The following is used for development purposes, by setting VK_ICD_FILENAMES.
noinst_DATA = dev_icd.json
dev_icd.json : dev_icd.json.in
$(AM_V_GEN) $(SED) \
-e "s#@build_libdir@#${abs_top_builddir}/${LIB_DIR}#" \
< $(srcdir)/dev_icd.json.in > $@
include $(top_srcdir)/install-lib-links.mk
noinst_HEADERS =
LDADD = \
$(PTHREAD_LIBS) -lm -lstdc++

View File

@ -0,0 +1,67 @@
# Copyright © 2016 Red Hat
#
# 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.
RADV_WS_AMDGPU_FILES := \
winsys/amdgpu/radv_amdgpu_bo.c \
winsys/amdgpu/radv_amdgpu_cs.c \
winsys/amdgpu/radv_amdgpu_surface.c \
winsys/amdgpu/radv_amdgpu_winsys.c \
winsys/amdgpu/radv_amdgpu_winsys.h
VULKAN_FILES := \
radv_cmd_buffer.c \
radv_device.c \
radv_descriptor_set.c \
radv_formats.c \
radv_image.c \
radv_meta.c \
radv_meta.h \
radv_meta_blit.c \
radv_meta_blit2d.c \
radv_meta_buffer.c \
radv_meta_bufimage.c \
radv_meta_clear.c \
radv_meta_copy.c \
radv_meta_decompress.c \
radv_meta_fast_clear.c \
radv_meta_resolve.c \
radv_meta_resolve_cs.c \
radv_pass.c \
radv_pipeline.c \
radv_pipeline_cache.c \
radv_query.c \
radv_util.c \
radv_wsi.c \
si_cmd_buffer.c \
vk_format_table.c \
$(RADV_WS_AMDGPU_FILES)
VULKAN_WSI_WAYLAND_FILES := \
radv_wsi_wayland.c
VULKAN_WSI_X11_FILES := \
radv_wsi_x11.c
VULKAN_GENERATED_FILES := \
radv_entrypoints.c \
radv_entrypoints.h \
radv_timestamp.h

View File

@ -0,0 +1,7 @@
{
"file_format_version": "1.0.0",
"ICD": {
"library_path": "@build_libdir@/libvulkan_radeon.so",
"abi_versions": "1.0.3"
}
}

View File

@ -0,0 +1,7 @@
{
"file_format_version": "1.0.0",
"ICD": {
"library_path": "libvulkan_radeon.so",
"abi_versions": "1.0.3"
}
}

File diff suppressed because it is too large Load Diff

117
src/amd/vulkan/radv_cs.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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.
*/
#pragma once
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include "r600d_common.h"
static inline unsigned radeon_check_space(struct radeon_winsys *ws,
struct radeon_winsys_cs *cs,
unsigned needed)
{
if (cs->max_dw - cs->cdw < needed)
ws->cs_grow(cs, needed);
return cs->cdw + needed;
}
static inline void radeon_set_config_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num)
{
assert(reg < R600_CONTEXT_REG_OFFSET);
assert(cs->cdw + 2 + num <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_CONFIG_REG, num, 0));
radeon_emit(cs, (reg - R600_CONFIG_REG_OFFSET) >> 2);
}
static inline void radeon_set_config_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value)
{
radeon_set_config_reg_seq(cs, reg, 1);
radeon_emit(cs, value);
}
static inline void radeon_set_context_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num)
{
assert(reg >= R600_CONTEXT_REG_OFFSET);
assert(cs->cdw + 2 + num <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_CONTEXT_REG, num, 0));
radeon_emit(cs, (reg - R600_CONTEXT_REG_OFFSET) >> 2);
}
static inline void radeon_set_context_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value)
{
radeon_set_context_reg_seq(cs, reg, 1);
radeon_emit(cs, value);
}
static inline void radeon_set_context_reg_idx(struct radeon_winsys_cs *cs,
unsigned reg, unsigned idx,
unsigned value)
{
assert(reg >= R600_CONTEXT_REG_OFFSET);
assert(cs->cdw + 3 <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_CONTEXT_REG, 1, 0));
radeon_emit(cs, (reg - R600_CONTEXT_REG_OFFSET) >> 2 | (idx << 28));
radeon_emit(cs, value);
}
static inline void radeon_set_sh_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num)
{
assert(reg >= SI_SH_REG_OFFSET && reg < SI_SH_REG_END);
assert(cs->cdw + 2 + num <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_SH_REG, num, 0));
radeon_emit(cs, (reg - SI_SH_REG_OFFSET) >> 2);
}
static inline void radeon_set_sh_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value)
{
radeon_set_sh_reg_seq(cs, reg, 1);
radeon_emit(cs, value);
}
static inline void radeon_set_uconfig_reg_seq(struct radeon_winsys_cs *cs, unsigned reg, unsigned num)
{
assert(reg >= CIK_UCONFIG_REG_OFFSET && reg < CIK_UCONFIG_REG_END);
assert(cs->cdw + 2 + num <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_UCONFIG_REG, num, 0));
radeon_emit(cs, (reg - CIK_UCONFIG_REG_OFFSET) >> 2);
}
static inline void radeon_set_uconfig_reg(struct radeon_winsys_cs *cs, unsigned reg, unsigned value)
{
radeon_set_uconfig_reg_seq(cs, reg, 1);
radeon_emit(cs, value);
}
static inline void radeon_set_uconfig_reg_idx(struct radeon_winsys_cs *cs,
unsigned reg, unsigned idx,
unsigned value)
{
assert(reg >= CIK_UCONFIG_REG_OFFSET && reg < CIK_UCONFIG_REG_END);
assert(cs->cdw + 3 <= cs->max_dw);
radeon_emit(cs, PKT3(PKT3_SET_UCONFIG_REG, 1, 0));
radeon_emit(cs, (reg - CIK_UCONFIG_REG_OFFSET) >> 2 | (idx << 28));
radeon_emit(cs, value);
}

View File

@ -0,0 +1,716 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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 <assert.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "util/mesa-sha1.h"
#include "radv_private.h"
#include "sid.h"
VkResult radv_CreateDescriptorSetLayout(
VkDevice _device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorSetLayout* pSetLayout)
{
RADV_FROM_HANDLE(radv_device, device, _device);
struct radv_descriptor_set_layout *set_layout;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO);
uint32_t max_binding = 0;
uint32_t immutable_sampler_count = 0;
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
max_binding = MAX(max_binding, pCreateInfo->pBindings[j].binding);
if (pCreateInfo->pBindings[j].pImmutableSamplers)
immutable_sampler_count += pCreateInfo->pBindings[j].descriptorCount;
}
size_t size = sizeof(struct radv_descriptor_set_layout) +
(max_binding + 1) * sizeof(set_layout->binding[0]) +
immutable_sampler_count * sizeof(struct radv_sampler *);
set_layout = radv_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!set_layout)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
/* We just allocate all the samplers at the end of the struct */
struct radv_sampler **samplers =
(struct radv_sampler **)&set_layout->binding[max_binding + 1];
set_layout->binding_count = max_binding + 1;
set_layout->shader_stages = 0;
set_layout->size = 0;
memset(set_layout->binding, 0, size - sizeof(struct radv_descriptor_set_layout));
uint32_t buffer_count = 0;
uint32_t dynamic_offset_count = 0;
for (uint32_t j = 0; j < pCreateInfo->bindingCount; j++) {
const VkDescriptorSetLayoutBinding *binding = &pCreateInfo->pBindings[j];
uint32_t b = binding->binding;
uint32_t alignment;
switch (binding->descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
set_layout->binding[b].dynamic_offset_count = 1;
set_layout->dynamic_shader_stages |= binding->stageFlags;
set_layout->binding[b].size = 0;
set_layout->binding[b].buffer_count = 1;
alignment = 1;
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
set_layout->binding[b].size = 16;
set_layout->binding[b].buffer_count = 1;
alignment = 16;
break;
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
/* main descriptor + fmask descriptor */
set_layout->binding[b].size = 64;
set_layout->binding[b].buffer_count = 1;
alignment = 32;
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
/* main descriptor + fmask descriptor + sampler */
set_layout->binding[b].size = 96;
set_layout->binding[b].buffer_count = 1;
alignment = 32;
break;
case VK_DESCRIPTOR_TYPE_SAMPLER:
set_layout->binding[b].size = 16;
alignment = 16;
break;
default:
break;
}
set_layout->size = align(set_layout->size, alignment);
assert(binding->descriptorCount > 0);
set_layout->binding[b].type = binding->descriptorType;
set_layout->binding[b].array_size = binding->descriptorCount;
set_layout->binding[b].offset = set_layout->size;
set_layout->binding[b].buffer_offset = buffer_count;
set_layout->binding[b].dynamic_offset_offset = dynamic_offset_count;
set_layout->size += binding->descriptorCount * set_layout->binding[b].size;
buffer_count += binding->descriptorCount * set_layout->binding[b].buffer_count;
dynamic_offset_count += binding->descriptorCount *
set_layout->binding[b].dynamic_offset_count;
if (binding->pImmutableSamplers) {
set_layout->binding[b].immutable_samplers = samplers;
samplers += binding->descriptorCount;
for (uint32_t i = 0; i < binding->descriptorCount; i++)
set_layout->binding[b].immutable_samplers[i] =
radv_sampler_from_handle(binding->pImmutableSamplers[i]);
} else {
set_layout->binding[b].immutable_samplers = NULL;
}
set_layout->shader_stages |= binding->stageFlags;
}
set_layout->buffer_count = buffer_count;
set_layout->dynamic_offset_count = dynamic_offset_count;
*pSetLayout = radv_descriptor_set_layout_to_handle(set_layout);
return VK_SUCCESS;
}
void radv_DestroyDescriptorSetLayout(
VkDevice _device,
VkDescriptorSetLayout _set_layout,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_descriptor_set_layout, set_layout, _set_layout);
if (!set_layout)
return;
radv_free2(&device->alloc, pAllocator, set_layout);
}
/*
* Pipeline layouts. These have nothing to do with the pipeline. They are
* just muttiple descriptor set layouts pasted together
*/
VkResult radv_CreatePipelineLayout(
VkDevice _device,
const VkPipelineLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkPipelineLayout* pPipelineLayout)
{
RADV_FROM_HANDLE(radv_device, device, _device);
struct radv_pipeline_layout *layout;
struct mesa_sha1 *ctx;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO);
layout = radv_alloc2(&device->alloc, pAllocator, sizeof(*layout), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (layout == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
layout->num_sets = pCreateInfo->setLayoutCount;
unsigned dynamic_offset_count = 0;
ctx = _mesa_sha1_init();
for (uint32_t set = 0; set < pCreateInfo->setLayoutCount; set++) {
RADV_FROM_HANDLE(radv_descriptor_set_layout, set_layout,
pCreateInfo->pSetLayouts[set]);
layout->set[set].layout = set_layout;
layout->set[set].dynamic_offset_start = dynamic_offset_count;
for (uint32_t b = 0; b < set_layout->binding_count; b++) {
dynamic_offset_count += set_layout->binding[b].array_size * set_layout->binding[b].dynamic_offset_count;
}
_mesa_sha1_update(ctx, set_layout->binding,
sizeof(set_layout->binding[0]) * set_layout->binding_count);
}
layout->dynamic_offset_count = dynamic_offset_count;
layout->push_constant_size = 0;
for (unsigned i = 0; i < pCreateInfo->pushConstantRangeCount; ++i) {
const VkPushConstantRange *range = pCreateInfo->pPushConstantRanges + i;
layout->push_constant_size = MAX2(layout->push_constant_size,
range->offset + range->size);
}
layout->push_constant_size = align(layout->push_constant_size, 16);
_mesa_sha1_update(ctx, &layout->push_constant_size,
sizeof(layout->push_constant_size));
_mesa_sha1_final(ctx, layout->sha1);
*pPipelineLayout = radv_pipeline_layout_to_handle(layout);
return VK_SUCCESS;
}
void radv_DestroyPipelineLayout(
VkDevice _device,
VkPipelineLayout _pipelineLayout,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_pipeline_layout, pipeline_layout, _pipelineLayout);
if (!pipeline_layout)
return;
radv_free2(&device->alloc, pAllocator, pipeline_layout);
}
#define EMPTY 1
static VkResult
radv_descriptor_set_create(struct radv_device *device,
struct radv_descriptor_pool *pool,
struct radv_cmd_buffer *cmd_buffer,
const struct radv_descriptor_set_layout *layout,
struct radv_descriptor_set **out_set)
{
struct radv_descriptor_set *set;
unsigned mem_size = sizeof(struct radv_descriptor_set) +
sizeof(struct radeon_winsys_bo *) * layout->buffer_count;
set = radv_alloc2(&device->alloc, NULL, mem_size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!set)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
memset(set, 0, mem_size);
if (layout->dynamic_offset_count) {
unsigned size = sizeof(struct radv_descriptor_range) *
layout->dynamic_offset_count;
set->dynamic_descriptors = radv_alloc2(&device->alloc, NULL, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!set->dynamic_descriptors) {
radv_free2(&device->alloc, NULL, set);
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
}
}
set->layout = layout;
if (layout->size) {
uint32_t layout_size = align_u32(layout->size, 32);
set->size = layout->size;
if (!cmd_buffer) {
if (pool->current_offset + layout_size <= pool->size) {
set->bo = pool->bo;
set->mapped_ptr = (uint32_t*)(pool->mapped_ptr + pool->current_offset);
set->va = device->ws->buffer_get_va(set->bo) + pool->current_offset;
pool->current_offset += layout_size;
} else {
int entry = pool->free_list, prev_entry = -1;
uint32_t offset;
while (entry >= 0) {
if (pool->free_nodes[entry].size >= layout_size) {
if (prev_entry >= 0)
pool->free_nodes[prev_entry].next = pool->free_nodes[entry].next;
else
pool->free_list = pool->free_nodes[entry].next;
break;
}
prev_entry = entry;
entry = pool->free_nodes[entry].next;
}
if (entry < 0) {
radv_free2(&device->alloc, NULL, set);
return vk_error(VK_ERROR_OUT_OF_DEVICE_MEMORY);
}
offset = pool->free_nodes[entry].offset;
pool->free_nodes[entry].next = pool->full_list;
pool->full_list = entry;
set->bo = pool->bo;
set->mapped_ptr = (uint32_t*)(pool->mapped_ptr + offset);
set->va = device->ws->buffer_get_va(set->bo) + offset;
}
} else {
unsigned bo_offset;
if (!radv_cmd_buffer_upload_alloc(cmd_buffer, set->size, 32,
&bo_offset,
(void**)&set->mapped_ptr)) {
radv_free2(&device->alloc, NULL, set->dynamic_descriptors);
radv_free2(&device->alloc, NULL, set);
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
}
set->va = device->ws->buffer_get_va(cmd_buffer->upload.upload_bo);
set->va += bo_offset;
}
}
if (pool)
list_add(&set->descriptor_pool, &pool->descriptor_sets);
else
list_inithead(&set->descriptor_pool);
for (unsigned i = 0; i < layout->binding_count; ++i) {
if (!layout->binding[i].immutable_samplers)
continue;
unsigned offset = layout->binding[i].offset / 4;
if (layout->binding[i].type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)
offset += 16;
for (unsigned j = 0; j < layout->binding[i].array_size; ++j) {
struct radv_sampler* sampler = layout->binding[i].immutable_samplers[j];
memcpy(set->mapped_ptr + offset, &sampler->state, 16);
offset += layout->binding[i].size / 4;
}
}
*out_set = set;
return VK_SUCCESS;
}
static void
radv_descriptor_set_destroy(struct radv_device *device,
struct radv_descriptor_pool *pool,
struct radv_descriptor_set *set,
bool free_bo)
{
if (free_bo && set->size) {
assert(pool->full_list >= 0);
int next = pool->free_nodes[pool->full_list].next;
pool->free_nodes[pool->full_list].next = pool->free_list;
pool->free_nodes[pool->full_list].offset = (uint8_t*)set->mapped_ptr - pool->mapped_ptr;
pool->free_nodes[pool->full_list].size = align_u32(set->size, 32);
pool->free_list = pool->full_list;
pool->full_list = next;
}
if (set->dynamic_descriptors)
radv_free2(&device->alloc, NULL, set->dynamic_descriptors);
if (!list_empty(&set->descriptor_pool))
list_del(&set->descriptor_pool);
radv_free2(&device->alloc, NULL, set);
}
VkResult
radv_temp_descriptor_set_create(struct radv_device *device,
struct radv_cmd_buffer *cmd_buffer,
VkDescriptorSetLayout _layout,
VkDescriptorSet *_set)
{
RADV_FROM_HANDLE(radv_descriptor_set_layout, layout, _layout);
struct radv_descriptor_set *set;
VkResult ret;
ret = radv_descriptor_set_create(device, NULL, cmd_buffer, layout, &set);
*_set = radv_descriptor_set_to_handle(set);
return ret;
}
void
radv_temp_descriptor_set_destroy(struct radv_device *device,
VkDescriptorSet _set)
{
RADV_FROM_HANDLE(radv_descriptor_set, set, _set);
radv_descriptor_set_destroy(device, NULL, set, false);
}
VkResult radv_CreateDescriptorPool(
VkDevice _device,
const VkDescriptorPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorPool* pDescriptorPool)
{
RADV_FROM_HANDLE(radv_device, device, _device);
struct radv_descriptor_pool *pool;
unsigned max_sets = pCreateInfo->maxSets * 2;
int size = sizeof(struct radv_descriptor_pool) +
max_sets * sizeof(struct radv_descriptor_pool_free_node);
uint64_t bo_size = 0;
pool = radv_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!pool)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
memset(pool, 0, sizeof(*pool));
pool->free_list = -1;
pool->full_list = 0;
pool->free_nodes[max_sets - 1].next = -1;
pool->max_sets = max_sets;
for (int i = 0; i + 1 < max_sets; ++i)
pool->free_nodes[i].next = i + 1;
for (unsigned i = 0; i < pCreateInfo->poolSizeCount; ++i) {
switch(pCreateInfo->pPoolSizes[i].type) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_SAMPLER:
/* 32 as we may need to align for images */
bo_size += 32 * pCreateInfo->pPoolSizes[i].descriptorCount;
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
bo_size += 64 * pCreateInfo->pPoolSizes[i].descriptorCount;
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
bo_size += 96 * pCreateInfo->pPoolSizes[i].descriptorCount;
break;
default:
unreachable("unknown descriptor type\n");
break;
}
}
if (bo_size) {
pool->bo = device->ws->buffer_create(device->ws, bo_size,
32, RADEON_DOMAIN_VRAM, 0);
pool->mapped_ptr = (uint8_t*)device->ws->buffer_map(pool->bo);
}
pool->size = bo_size;
list_inithead(&pool->descriptor_sets);
*pDescriptorPool = radv_descriptor_pool_to_handle(pool);
return VK_SUCCESS;
}
void radv_DestroyDescriptorPool(
VkDevice _device,
VkDescriptorPool _pool,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_descriptor_pool, pool, _pool);
if (!pool)
return;
list_for_each_entry_safe(struct radv_descriptor_set, set,
&pool->descriptor_sets, descriptor_pool) {
radv_descriptor_set_destroy(device, pool, set, false);
}
if (pool->bo)
device->ws->buffer_destroy(pool->bo);
radv_free2(&device->alloc, pAllocator, pool);
}
VkResult radv_ResetDescriptorPool(
VkDevice _device,
VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags flags)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_descriptor_pool, pool, descriptorPool);
list_for_each_entry_safe(struct radv_descriptor_set, set,
&pool->descriptor_sets, descriptor_pool) {
radv_descriptor_set_destroy(device, pool, set, false);
}
pool->current_offset = 0;
pool->free_list = -1;
pool->full_list = 0;
pool->free_nodes[pool->max_sets - 1].next = -1;
for (int i = 0; i + 1 < pool->max_sets; ++i)
pool->free_nodes[i].next = i + 1;
return VK_SUCCESS;
}
VkResult radv_AllocateDescriptorSets(
VkDevice _device,
const VkDescriptorSetAllocateInfo* pAllocateInfo,
VkDescriptorSet* pDescriptorSets)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_descriptor_pool, pool, pAllocateInfo->descriptorPool);
VkResult result = VK_SUCCESS;
uint32_t i;
struct radv_descriptor_set *set;
/* allocate a set of buffers for each shader to contain descriptors */
for (i = 0; i < pAllocateInfo->descriptorSetCount; i++) {
RADV_FROM_HANDLE(radv_descriptor_set_layout, layout,
pAllocateInfo->pSetLayouts[i]);
result = radv_descriptor_set_create(device, pool, NULL, layout, &set);
if (result != VK_SUCCESS)
break;
pDescriptorSets[i] = radv_descriptor_set_to_handle(set);
}
if (result != VK_SUCCESS)
radv_FreeDescriptorSets(_device, pAllocateInfo->descriptorPool,
i, pDescriptorSets);
return result;
}
VkResult radv_FreeDescriptorSets(
VkDevice _device,
VkDescriptorPool descriptorPool,
uint32_t count,
const VkDescriptorSet* pDescriptorSets)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_descriptor_pool, pool, descriptorPool);
for (uint32_t i = 0; i < count; i++) {
RADV_FROM_HANDLE(radv_descriptor_set, set, pDescriptorSets[i]);
if (set)
radv_descriptor_set_destroy(device, pool, set, true);
}
return VK_SUCCESS;
}
static void write_texel_buffer_descriptor(struct radv_device *device,
unsigned *dst,
struct radeon_winsys_bo **buffer_list,
const VkBufferView _buffer_view)
{
RADV_FROM_HANDLE(radv_buffer_view, buffer_view, _buffer_view);
memcpy(dst, buffer_view->state, 4 * 4);
*buffer_list = buffer_view->bo;
}
static void write_buffer_descriptor(struct radv_device *device,
unsigned *dst,
struct radeon_winsys_bo **buffer_list,
const VkDescriptorBufferInfo *buffer_info)
{
RADV_FROM_HANDLE(radv_buffer, buffer, buffer_info->buffer);
uint64_t va = device->ws->buffer_get_va(buffer->bo);
uint32_t range = buffer_info->range;
if (buffer_info->range == VK_WHOLE_SIZE)
range = buffer->size - buffer_info->offset;
va += buffer_info->offset + buffer->offset;
dst[0] = va;
dst[1] = S_008F04_BASE_ADDRESS_HI(va >> 32);
dst[2] = range;
dst[3] = S_008F0C_DST_SEL_X(V_008F0C_SQ_SEL_X) |
S_008F0C_DST_SEL_Y(V_008F0C_SQ_SEL_Y) |
S_008F0C_DST_SEL_Z(V_008F0C_SQ_SEL_Z) |
S_008F0C_DST_SEL_W(V_008F0C_SQ_SEL_W) |
S_008F0C_NUM_FORMAT(V_008F0C_BUF_NUM_FORMAT_FLOAT) |
S_008F0C_DATA_FORMAT(V_008F0C_BUF_DATA_FORMAT_32);
*buffer_list = buffer->bo;
}
static void write_dynamic_buffer_descriptor(struct radv_device *device,
struct radv_descriptor_range *range,
struct radeon_winsys_bo **buffer_list,
const VkDescriptorBufferInfo *buffer_info)
{
RADV_FROM_HANDLE(radv_buffer, buffer, buffer_info->buffer);
uint64_t va = device->ws->buffer_get_va(buffer->bo);
unsigned size = buffer_info->range;
if (buffer_info->range == VK_WHOLE_SIZE)
size = buffer->size - buffer_info->offset;
va += buffer_info->offset + buffer->offset;
range->va = va;
range->size = size;
*buffer_list = buffer->bo;
}
static void
write_image_descriptor(struct radv_device *device,
unsigned *dst,
struct radeon_winsys_bo **buffer_list,
const VkDescriptorImageInfo *image_info)
{
RADV_FROM_HANDLE(radv_image_view, iview, image_info->imageView);
memcpy(dst, iview->descriptor, 8 * 4);
memcpy(dst + 8, iview->fmask_descriptor, 8 * 4);
*buffer_list = iview->bo;
}
static void
write_combined_image_sampler_descriptor(struct radv_device *device,
unsigned *dst,
struct radeon_winsys_bo **buffer_list,
const VkDescriptorImageInfo *image_info,
bool has_sampler)
{
RADV_FROM_HANDLE(radv_sampler, sampler, image_info->sampler);
write_image_descriptor(device, dst, buffer_list, image_info);
/* copy over sampler state */
if (has_sampler)
memcpy(dst + 16, sampler->state, 16);
}
static void
write_sampler_descriptor(struct radv_device *device,
unsigned *dst,
const VkDescriptorImageInfo *image_info)
{
RADV_FROM_HANDLE(radv_sampler, sampler, image_info->sampler);
memcpy(dst, sampler->state, 16);
}
void radv_UpdateDescriptorSets(
VkDevice _device,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites,
uint32_t descriptorCopyCount,
const VkCopyDescriptorSet* pDescriptorCopies)
{
RADV_FROM_HANDLE(radv_device, device, _device);
uint32_t i, j;
for (i = 0; i < descriptorWriteCount; i++) {
const VkWriteDescriptorSet *writeset = &pDescriptorWrites[i];
RADV_FROM_HANDLE(radv_descriptor_set, set, writeset->dstSet);
const struct radv_descriptor_set_binding_layout *binding_layout =
set->layout->binding + writeset->dstBinding;
uint32_t *ptr = set->mapped_ptr;
struct radeon_winsys_bo **buffer_list = set->descriptors;
ptr += binding_layout->offset / 4;
ptr += binding_layout->size * writeset->dstArrayElement / 4;
buffer_list += binding_layout->buffer_offset;
buffer_list += binding_layout->buffer_count * writeset->dstArrayElement;
for (j = 0; j < writeset->descriptorCount; ++j) {
switch(writeset->descriptorType) {
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC: {
unsigned idx = writeset->dstArrayElement + j;
idx += binding_layout->dynamic_offset_offset;
write_dynamic_buffer_descriptor(device, set->dynamic_descriptors + idx,
buffer_list, writeset->pBufferInfo + j);
break;
}
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:
write_buffer_descriptor(device, ptr, buffer_list,
writeset->pBufferInfo + j);
break;
case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:
case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:
write_texel_buffer_descriptor(device, ptr, buffer_list,
writeset->pTexelBufferView[j]);
break;
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:
write_image_descriptor(device, ptr, buffer_list,
writeset->pImageInfo + j);
break;
case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
write_combined_image_sampler_descriptor(device, ptr, buffer_list,
writeset->pImageInfo + j,
!binding_layout->immutable_samplers);
break;
case VK_DESCRIPTOR_TYPE_SAMPLER:
assert(!binding_layout->immutable_samplers);
write_sampler_descriptor(device, ptr,
writeset->pImageInfo + j);
break;
default:
unreachable("unimplemented descriptor type");
break;
}
ptr += binding_layout->size / 4;
buffer_list += binding_layout->buffer_count;
}
}
if (descriptorCopyCount)
radv_finishme("copy descriptors");
}

View File

@ -0,0 +1,81 @@
/*
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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.
*/
#pragma once
#include <vulkan/vulkan.h>
#define MAX_SETS 8
struct radv_descriptor_set_binding_layout {
VkDescriptorType type;
/* Number of array elements in this binding */
uint16_t array_size;
uint16_t offset;
uint16_t buffer_offset;
uint16_t dynamic_offset_offset;
/* redundant with the type, each for a single array element */
uint16_t size;
uint16_t buffer_count;
uint16_t dynamic_offset_count;
/* Immutable samplers (or NULL if no immutable samplers) */
struct radv_sampler **immutable_samplers;
};
struct radv_descriptor_set_layout {
/* Number of bindings in this descriptor set */
uint16_t binding_count;
/* Total size of the descriptor set with room for all array entries */
uint16_t size;
/* Shader stages affected by this descriptor set */
uint16_t shader_stages;
uint16_t dynamic_shader_stages;
/* Number of buffers in this descriptor set */
uint16_t buffer_count;
/* Number of dynamic offsets used by this descriptor set */
uint16_t dynamic_offset_count;
/* Bindings in this descriptor set */
struct radv_descriptor_set_binding_layout binding[0];
};
struct radv_pipeline_layout {
struct {
struct radv_descriptor_set_layout *layout;
uint32_t size;
uint32_t dynamic_offset_start;
} set[MAX_SETS];
uint32_t num_sets;
uint32_t push_constant_size;
uint32_t dynamic_offset_count;
unsigned char sha1[20];
};

1782
src/amd/vulkan/radv_device.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*
* Copyright © 2016 Red Hat.
*
* 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.
*/
#pragma once
#include <amdgpu.h>
#include "radv_radeon_winsys.h"
struct radv_device_info {
uint32_t pci_id;
enum chip_class chip_class;
};

View File

@ -0,0 +1,351 @@
# coding=utf-8
#
# Copyright © 2015 Intel 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.
#
import fileinput, re, sys
# Each function typedef in the vulkan.h header is all on one line and matches
# this regepx. We hope that won't change.
p = re.compile('typedef ([^ ]*) *\((?:VKAPI_PTR)? *\*PFN_vk([^(]*)\)(.*);')
entrypoints = []
# We generate a static hash table for entry point lookup
# (vkGetProcAddress). We use a linear congruential generator for our hash
# function and a power-of-two size table. The prime numbers are determined
# experimentally.
none = 0xffff
hash_size = 256
u32_mask = 2**32 - 1
hash_mask = hash_size - 1
prime_factor = 5024183
prime_step = 19
def hash(name):
h = 0;
for c in name:
h = (h * prime_factor + ord(c)) & u32_mask
return h
def get_platform_guard_macro(name):
if "Xlib" in name:
return "VK_USE_PLATFORM_XLIB_KHR"
elif "Xcb" in name:
return "VK_USE_PLATFORM_XCB_KHR"
elif "Wayland" in name:
return "VK_USE_PLATFORM_WAYLAND_KHR"
elif "Mir" in name:
return "VK_USE_PLATFORM_MIR_KHR"
elif "Android" in name:
return "VK_USE_PLATFORM_ANDROID_KHR"
elif "Win32" in name:
return "VK_USE_PLATFORM_WIN32_KHR"
else:
return None
def print_guard_start(name):
guard = get_platform_guard_macro(name)
if guard is not None:
print "#ifdef {0}".format(guard)
def print_guard_end(name):
guard = get_platform_guard_macro(name)
if guard is not None:
print "#endif // {0}".format(guard)
opt_header = False
opt_code = False
if (sys.argv[1] == "header"):
opt_header = True
sys.argv.pop()
elif (sys.argv[1] == "code"):
opt_code = True
sys.argv.pop()
# Parse the entry points in the header
i = 0
for line in fileinput.input():
m = p.match(line)
if (m):
if m.group(2) == 'VoidFunction':
continue
fullname = "vk" + m.group(2)
h = hash(fullname)
entrypoints.append((m.group(1), m.group(2), m.group(3), i, h))
i = i + 1
# For outputting entrypoints.h we generate a radv_EntryPoint() prototype
# per entry point.
if opt_header:
print "/* This file generated from vk_gen.py, don't edit directly. */\n"
print "struct radv_dispatch_table {"
print " union {"
print " void *entrypoints[%d];" % len(entrypoints)
print " struct {"
for type, name, args, num, h in entrypoints:
guard = get_platform_guard_macro(name)
if guard is not None:
print "#ifdef {0}".format(guard)
print " PFN_vk{0} {0};".format(name)
print "#else"
print " void *{0};".format(name)
print "#endif"
else:
print " PFN_vk{0} {0};".format(name)
print " };\n"
print " };\n"
print "};\n"
print "void radv_set_dispatch_devinfo(const struct radv_device_info *info);\n"
for type, name, args, num, h in entrypoints:
print_guard_start(name)
print "%s radv_%s%s;" % (type, name, args)
print "%s vi_%s%s;" % (type, name, args)
print "%s cik_%s%s;" % (type, name, args)
print "%s si_%s%s;" % (type, name, args)
print "%s radv_validate_%s%s;" % (type, name, args)
print_guard_end(name)
exit()
print """/*
* Copyright © 2015 Intel 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.
*/
/* DO NOT EDIT! This is a generated file. */
#include "radv_private.h"
struct radv_entrypoint {
uint32_t name;
uint32_t hash;
};
/* We use a big string constant to avoid lots of reloctions from the entry
* point table to lots of little strings. The entries in the entry point table
* store the index into this big string.
*/
static const char strings[] ="""
offsets = []
i = 0;
for type, name, args, num, h in entrypoints:
print " \"vk%s\\0\"" % name
offsets.append(i)
i += 2 + len(name) + 1
print " ;"
# Now generate the table of all entry points and their validation functions
print "\nstatic const struct radv_entrypoint entrypoints[] = {"
for type, name, args, num, h in entrypoints:
print " { %5d, 0x%08x }," % (offsets[num], h)
print "};\n"
print """
/* Weak aliases for all potential implementations. These will resolve to
* NULL if they're not defined, which lets the resolve_entrypoint() function
* either pick the correct entry point.
*/
"""
for layer in [ "radv", "validate", "si", "cik", "vi" ]:
for type, name, args, num, h in entrypoints:
print_guard_start(name)
print "%s %s_%s%s __attribute__ ((weak));" % (type, layer, name, args)
print_guard_end(name)
print "\nconst struct radv_dispatch_table %s_layer = {" % layer
for type, name, args, num, h in entrypoints:
print_guard_start(name)
print " .%s = %s_%s," % (name, layer, name)
print_guard_end(name)
print "};\n"
print """
#ifdef DEBUG
static bool enable_validate = true;
#else
static bool enable_validate = false;
#endif
/* We can't use symbols that need resolving (like, oh, getenv) in the resolve
* function. This means that we have to determine whether or not to use the
* validation layer sometime before that. The constructor function attribute asks
* the dynamic linker to invoke determine_validate() at dlopen() time which
* works.
*/
static void __attribute__ ((constructor))
determine_validate(void)
{
const char *s = getenv("ANV_VALIDATE");
if (s)
enable_validate = atoi(s);
}
static const struct radv_device_info *dispatch_devinfo;
void
radv_set_dispatch_devinfo(const struct radv_device_info *devinfo)
{
dispatch_devinfo = devinfo;
}
void * __attribute__ ((noinline))
radv_resolve_entrypoint(uint32_t index)
{
if (enable_validate && validate_layer.entrypoints[index])
return validate_layer.entrypoints[index];
if (dispatch_devinfo == NULL) {
return radv_layer.entrypoints[index];
}
switch (dispatch_devinfo->chip_class) {
case VI:
if (vi_layer.entrypoints[index])
return vi_layer.entrypoints[index];
/* fall through */
case CIK:
if (cik_layer.entrypoints[index])
return cik_layer.entrypoints[index];
/* fall through */
case SI:
if (si_layer.entrypoints[index])
return si_layer.entrypoints[index];
/* fall through */
case 0:
return radv_layer.entrypoints[index];
default:
unreachable("unsupported gen\\n");
}
}
"""
# Now generate the hash table used for entry point look up. This is a
# uint16_t table of entry point indices. We use 0xffff to indicate an entry
# in the hash table is empty.
map = [none for f in xrange(hash_size)]
collisions = [0 for f in xrange(10)]
for type, name, args, num, h in entrypoints:
level = 0
while map[h & hash_mask] != none:
h = h + prime_step
level = level + 1
if level > 9:
collisions[9] += 1
else:
collisions[level] += 1
map[h & hash_mask] = num
print "/* Hash table stats:"
print " * size %d entries" % hash_size
print " * collisions entries"
for i in xrange(10):
if (i == 9):
plus = "+"
else:
plus = " "
print " * %2d%s %4d" % (i, plus, collisions[i])
print " */\n"
print "#define none 0x%04x\n" % none
print "static const uint16_t map[] = {"
for i in xrange(0, hash_size, 8):
print " ",
for j in xrange(i, i + 8):
if map[j] & 0xffff == 0xffff:
print " none,",
else:
print "0x%04x," % (map[j] & 0xffff),
print
print "};"
# Finally we generate the hash table lookup function. The hash function and
# linear probing algorithm matches the hash table generated above.
print """
void *
radv_lookup_entrypoint(const char *name)
{
static const uint32_t prime_factor = %d;
static const uint32_t prime_step = %d;
const struct radv_entrypoint *e;
uint32_t hash, h, i;
const char *p;
hash = 0;
for (p = name; *p; p++)
hash = hash * prime_factor + *p;
h = hash;
do {
i = map[h & %d];
if (i == none)
return NULL;
e = &entrypoints[i];
h += prime_step;
} while (e->hash != hash);
if (strcmp(name, strings + e->name) != 0)
return NULL;
return radv_resolve_entrypoint(i);
}
""" % (prime_factor, prime_step, hash_mask)

File diff suppressed because it is too large Load Diff

1030
src/amd/vulkan/radv_image.c Normal file

File diff suppressed because it is too large Load Diff

388
src/amd/vulkan/radv_meta.c Normal file
View File

@ -0,0 +1,388 @@
/*
* Copyright © 2016 Red Hat
* based on intel anv code:
* Copyright © 2015 Intel 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 "radv_meta.h"
#include <fcntl.h>
#include <limits.h>
#include <pwd.h>
#include <sys/stat.h>
void
radv_meta_save(struct radv_meta_saved_state *state,
const struct radv_cmd_buffer *cmd_buffer,
uint32_t dynamic_mask)
{
state->old_pipeline = cmd_buffer->state.pipeline;
state->old_descriptor_set0 = cmd_buffer->state.descriptors[0];
memcpy(state->old_vertex_bindings, cmd_buffer->state.vertex_bindings,
sizeof(state->old_vertex_bindings));
state->dynamic_mask = dynamic_mask;
radv_dynamic_state_copy(&state->dynamic, &cmd_buffer->state.dynamic,
dynamic_mask);
memcpy(state->push_constants, cmd_buffer->push_constants, MAX_PUSH_CONSTANTS_SIZE);
}
void
radv_meta_restore(const struct radv_meta_saved_state *state,
struct radv_cmd_buffer *cmd_buffer)
{
cmd_buffer->state.pipeline = state->old_pipeline;
radv_bind_descriptor_set(cmd_buffer, state->old_descriptor_set0, 0);
memcpy(cmd_buffer->state.vertex_bindings, state->old_vertex_bindings,
sizeof(state->old_vertex_bindings));
cmd_buffer->state.vb_dirty |= (1 << RADV_META_VERTEX_BINDING_COUNT) - 1;
cmd_buffer->state.dirty |= RADV_CMD_DIRTY_PIPELINE;
radv_dynamic_state_copy(&cmd_buffer->state.dynamic, &state->dynamic,
state->dynamic_mask);
cmd_buffer->state.dirty |= state->dynamic_mask;
memcpy(cmd_buffer->push_constants, state->push_constants, MAX_PUSH_CONSTANTS_SIZE);
cmd_buffer->push_constant_stages |= VK_SHADER_STAGE_ALL_GRAPHICS | VK_SHADER_STAGE_COMPUTE_BIT;
}
void
radv_meta_save_pass(struct radv_meta_saved_pass_state *state,
const struct radv_cmd_buffer *cmd_buffer)
{
state->pass = cmd_buffer->state.pass;
state->subpass = cmd_buffer->state.subpass;
state->framebuffer = cmd_buffer->state.framebuffer;
state->attachments = cmd_buffer->state.attachments;
state->render_area = cmd_buffer->state.render_area;
}
void
radv_meta_restore_pass(const struct radv_meta_saved_pass_state *state,
struct radv_cmd_buffer *cmd_buffer)
{
cmd_buffer->state.pass = state->pass;
cmd_buffer->state.subpass = state->subpass;
cmd_buffer->state.framebuffer = state->framebuffer;
cmd_buffer->state.attachments = state->attachments;
cmd_buffer->state.render_area = state->render_area;
if (state->subpass)
radv_emit_framebuffer_state(cmd_buffer);
}
void
radv_meta_save_compute(struct radv_meta_saved_compute_state *state,
const struct radv_cmd_buffer *cmd_buffer,
unsigned push_constant_size)
{
state->old_pipeline = cmd_buffer->state.compute_pipeline;
state->old_descriptor_set0 = cmd_buffer->state.descriptors[0];
if (push_constant_size)
memcpy(state->push_constants, cmd_buffer->push_constants, push_constant_size);
}
void
radv_meta_restore_compute(const struct radv_meta_saved_compute_state *state,
struct radv_cmd_buffer *cmd_buffer,
unsigned push_constant_size)
{
radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer), VK_PIPELINE_BIND_POINT_COMPUTE,
radv_pipeline_to_handle(state->old_pipeline));
radv_bind_descriptor_set(cmd_buffer, state->old_descriptor_set0, 0);
if (push_constant_size) {
memcpy(cmd_buffer->push_constants, state->push_constants, push_constant_size);
cmd_buffer->push_constant_stages |= VK_SHADER_STAGE_COMPUTE_BIT;
}
}
VkImageViewType
radv_meta_get_view_type(const struct radv_image *image)
{
switch (image->type) {
case VK_IMAGE_TYPE_1D: return VK_IMAGE_VIEW_TYPE_1D;
case VK_IMAGE_TYPE_2D: return VK_IMAGE_VIEW_TYPE_2D;
case VK_IMAGE_TYPE_3D: return VK_IMAGE_VIEW_TYPE_3D;
default:
unreachable("bad VkImageViewType");
}
}
/**
* When creating a destination VkImageView, this function provides the needed
* VkImageViewCreateInfo::subresourceRange::baseArrayLayer.
*/
uint32_t
radv_meta_get_iview_layer(const struct radv_image *dest_image,
const VkImageSubresourceLayers *dest_subresource,
const VkOffset3D *dest_offset)
{
switch (dest_image->type) {
case VK_IMAGE_TYPE_1D:
case VK_IMAGE_TYPE_2D:
return dest_subresource->baseArrayLayer;
case VK_IMAGE_TYPE_3D:
/* HACK: Vulkan does not allow attaching a 3D image to a framebuffer,
* but meta does it anyway. When doing so, we translate the
* destination's z offset into an array offset.
*/
return dest_offset->z;
default:
assert(!"bad VkImageType");
return 0;
}
}
static void *
meta_alloc(void* _device, size_t size, size_t alignment,
VkSystemAllocationScope allocationScope)
{
struct radv_device *device = _device;
return device->alloc.pfnAllocation(device->alloc.pUserData, size, alignment,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
}
static void *
meta_realloc(void* _device, void *original, size_t size, size_t alignment,
VkSystemAllocationScope allocationScope)
{
struct radv_device *device = _device;
return device->alloc.pfnReallocation(device->alloc.pUserData, original,
size, alignment,
VK_SYSTEM_ALLOCATION_SCOPE_DEVICE);
}
static void
meta_free(void* _device, void *data)
{
struct radv_device *device = _device;
return device->alloc.pfnFree(device->alloc.pUserData, data);
}
static bool
radv_builtin_cache_path(char *path)
{
char *xdg_cache_home = getenv("XDG_CACHE_HOME");
const char *suffix = "/radv_builtin_shaders";
const char *suffix2 = "/.cache/radv_builtin_shaders";
struct passwd pwd, *result;
char path2[PATH_MAX + 1]; /* PATH_MAX is not a real max,but suffices here. */
if (xdg_cache_home) {
if (strlen(xdg_cache_home) + strlen(suffix) > PATH_MAX)
return false;
strcpy(path, xdg_cache_home);
strcat(path, suffix);
return true;
}
getpwuid_r(getuid(), &pwd, path2, PATH_MAX - strlen(suffix2), &result);
if (!result)
return false;
strcpy(path, pwd.pw_dir);
strcat(path, "/.cache");
mkdir(path, 0755);
strcat(path, suffix);
return true;
}
static void
radv_load_meta_pipeline(struct radv_device *device)
{
char path[PATH_MAX + 1];
struct stat st;
void *data = NULL;
if (!radv_builtin_cache_path(path))
return;
int fd = open(path, O_RDONLY);
if (fd < 0)
return;
if (fstat(fd, &st))
goto fail;
data = malloc(st.st_size);
if (!data)
goto fail;
if(read(fd, data, st.st_size) == -1)
goto fail;
radv_pipeline_cache_load(&device->meta_state.cache, data, st.st_size);
fail:
free(data);
close(fd);
}
static void
radv_store_meta_pipeline(struct radv_device *device)
{
char path[PATH_MAX + 1], path2[PATH_MAX + 7];
size_t size;
void *data = NULL;
if (!device->meta_state.cache.modified)
return;
if (radv_GetPipelineCacheData(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&size, NULL))
return;
if (!radv_builtin_cache_path(path))
return;
strcpy(path2, path);
strcat(path2, "XXXXXX");
int fd = mkstemp(path2);//open(path, O_WRONLY | O_CREAT, 0600);
if (fd < 0)
return;
data = malloc(size);
if (!data)
goto fail;
if (radv_GetPipelineCacheData(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&size, data))
goto fail;
if(write(fd, data, size) == -1)
goto fail;
rename(path2, path);
fail:
free(data);
close(fd);
unlink(path2);
}
VkResult
radv_device_init_meta(struct radv_device *device)
{
VkResult result;
device->meta_state.alloc = (VkAllocationCallbacks) {
.pUserData = device,
.pfnAllocation = meta_alloc,
.pfnReallocation = meta_realloc,
.pfnFree = meta_free,
};
device->meta_state.cache.alloc = device->meta_state.alloc;
radv_pipeline_cache_init(&device->meta_state.cache, device);
radv_load_meta_pipeline(device);
result = radv_device_init_meta_clear_state(device);
if (result != VK_SUCCESS)
goto fail_clear;
result = radv_device_init_meta_resolve_state(device);
if (result != VK_SUCCESS)
goto fail_resolve;
result = radv_device_init_meta_blit_state(device);
if (result != VK_SUCCESS)
goto fail_blit;
result = radv_device_init_meta_blit2d_state(device);
if (result != VK_SUCCESS)
goto fail_blit2d;
result = radv_device_init_meta_bufimage_state(device);
if (result != VK_SUCCESS)
goto fail_bufimage;
result = radv_device_init_meta_depth_decomp_state(device);
if (result != VK_SUCCESS)
goto fail_depth_decomp;
result = radv_device_init_meta_buffer_state(device);
if (result != VK_SUCCESS)
goto fail_buffer;
result = radv_device_init_meta_fast_clear_flush_state(device);
if (result != VK_SUCCESS)
goto fail_fast_clear;
result = radv_device_init_meta_resolve_compute_state(device);
if (result != VK_SUCCESS)
goto fail_resolve_compute;
return VK_SUCCESS;
fail_resolve_compute:
radv_device_finish_meta_fast_clear_flush_state(device);
fail_fast_clear:
radv_device_finish_meta_buffer_state(device);
fail_buffer:
radv_device_finish_meta_depth_decomp_state(device);
fail_depth_decomp:
radv_device_finish_meta_bufimage_state(device);
fail_bufimage:
radv_device_finish_meta_blit2d_state(device);
fail_blit2d:
radv_device_finish_meta_blit_state(device);
fail_blit:
radv_device_finish_meta_resolve_state(device);
fail_resolve:
radv_device_finish_meta_clear_state(device);
fail_clear:
radv_pipeline_cache_finish(&device->meta_state.cache);
return result;
}
void
radv_device_finish_meta(struct radv_device *device)
{
radv_device_finish_meta_clear_state(device);
radv_device_finish_meta_resolve_state(device);
radv_device_finish_meta_blit_state(device);
radv_device_finish_meta_blit2d_state(device);
radv_device_finish_meta_bufimage_state(device);
radv_device_finish_meta_depth_decomp_state(device);
radv_device_finish_meta_buffer_state(device);
radv_device_finish_meta_fast_clear_flush_state(device);
radv_device_finish_meta_resolve_compute_state(device);
radv_store_meta_pipeline(device);
radv_pipeline_cache_finish(&device->meta_state.cache);
}
/*
* The most common meta operations all want to have the viewport
* reset and any scissors disabled. The rest of the dynamic state
* should have no effect.
*/
void
radv_meta_save_graphics_reset_vport_scissor(struct radv_meta_saved_state *saved_state,
struct radv_cmd_buffer *cmd_buffer)
{
uint32_t dirty_state = (1 << VK_DYNAMIC_STATE_VIEWPORT) | (1 << VK_DYNAMIC_STATE_SCISSOR);
radv_meta_save(saved_state, cmd_buffer, dirty_state);
cmd_buffer->state.dynamic.viewport.count = 0;
cmd_buffer->state.dynamic.scissor.count = 0;
cmd_buffer->state.dirty |= dirty_state;
}

190
src/amd/vulkan/radv_meta.h Normal file
View File

@ -0,0 +1,190 @@
/*
* Copyright © 2016 Red Hat
* based on intel anv code:
* Copyright © 2015 Intel 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.
*/
#pragma once
#include "radv_private.h"
#ifdef __cplusplus
extern "C" {
#endif
#define RADV_META_VERTEX_BINDING_COUNT 2
struct radv_meta_saved_state {
struct radv_vertex_binding old_vertex_bindings[RADV_META_VERTEX_BINDING_COUNT];
struct radv_descriptor_set *old_descriptor_set0;
struct radv_pipeline *old_pipeline;
/**
* Bitmask of (1 << VK_DYNAMIC_STATE_*). Defines the set of saved dynamic
* state.
*/
uint32_t dynamic_mask;
struct radv_dynamic_state dynamic;
char push_constants[128];
};
struct radv_meta_saved_pass_state {
struct radv_render_pass *pass;
const struct radv_subpass *subpass;
struct radv_attachment_state *attachments;
struct radv_framebuffer *framebuffer;
VkRect2D render_area;
};
struct radv_meta_saved_compute_state {
struct radv_descriptor_set *old_descriptor_set0;
struct radv_pipeline *old_pipeline;
char push_constants[128];
};
VkResult radv_device_init_meta_clear_state(struct radv_device *device);
void radv_device_finish_meta_clear_state(struct radv_device *device);
VkResult radv_device_init_meta_resolve_state(struct radv_device *device);
void radv_device_finish_meta_resolve_state(struct radv_device *device);
VkResult radv_device_init_meta_depth_decomp_state(struct radv_device *device);
void radv_device_finish_meta_depth_decomp_state(struct radv_device *device);
VkResult radv_device_init_meta_fast_clear_flush_state(struct radv_device *device);
void radv_device_finish_meta_fast_clear_flush_state(struct radv_device *device);
VkResult radv_device_init_meta_blit_state(struct radv_device *device);
void radv_device_finish_meta_blit_state(struct radv_device *device);
VkResult radv_device_init_meta_blit2d_state(struct radv_device *device);
void radv_device_finish_meta_blit2d_state(struct radv_device *device);
VkResult radv_device_init_meta_buffer_state(struct radv_device *device);
void radv_device_finish_meta_buffer_state(struct radv_device *device);
VkResult radv_device_init_meta_resolve_compute_state(struct radv_device *device);
void radv_device_finish_meta_resolve_compute_state(struct radv_device *device);
void radv_meta_save(struct radv_meta_saved_state *state,
const struct radv_cmd_buffer *cmd_buffer,
uint32_t dynamic_mask);
void radv_meta_restore(const struct radv_meta_saved_state *state,
struct radv_cmd_buffer *cmd_buffer);
void radv_meta_save_pass(struct radv_meta_saved_pass_state *state,
const struct radv_cmd_buffer *cmd_buffer);
void radv_meta_restore_pass(const struct radv_meta_saved_pass_state *state,
struct radv_cmd_buffer *cmd_buffer);
void radv_meta_save_compute(struct radv_meta_saved_compute_state *state,
const struct radv_cmd_buffer *cmd_buffer,
unsigned push_constant_size);
void radv_meta_restore_compute(const struct radv_meta_saved_compute_state *state,
struct radv_cmd_buffer *cmd_buffer,
unsigned push_constant_size);
VkImageViewType radv_meta_get_view_type(const struct radv_image *image);
uint32_t radv_meta_get_iview_layer(const struct radv_image *dest_image,
const VkImageSubresourceLayers *dest_subresource,
const VkOffset3D *dest_offset);
struct radv_meta_blit2d_surf {
/** The size of an element in bytes. */
uint8_t bs;
VkFormat format;
struct radv_image *image;
unsigned level;
unsigned layer;
VkImageAspectFlags aspect_mask;
};
struct radv_meta_blit2d_buffer {
struct radv_buffer *buffer;
uint32_t offset;
uint32_t pitch;
uint8_t bs;
VkFormat format;
};
struct radv_meta_blit2d_rect {
uint32_t src_x, src_y;
uint32_t dst_x, dst_y;
uint32_t width, height;
};
void radv_meta_begin_blit2d(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_state *save);
void radv_meta_blit2d(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_surf *src_img,
struct radv_meta_blit2d_buffer *src_buf,
struct radv_meta_blit2d_surf *dst,
unsigned num_rects,
struct radv_meta_blit2d_rect *rects);
void radv_meta_end_blit2d(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_state *save);
VkResult radv_device_init_meta_bufimage_state(struct radv_device *device);
void radv_device_finish_meta_bufimage_state(struct radv_device *device);
void radv_meta_begin_bufimage(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_compute_state *save);
void radv_meta_end_bufimage(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_compute_state *save);
void radv_meta_image_to_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_surf *src,
struct radv_meta_blit2d_buffer *dst,
unsigned num_rects,
struct radv_meta_blit2d_rect *rects);
void radv_decompress_depth_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image,
VkImageSubresourceRange *subresourceRange);
void radv_resummarize_depth_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image,
VkImageSubresourceRange *subresourceRange);
void radv_fast_clear_flush_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image);
void radv_meta_save_graphics_reset_vport_scissor(struct radv_meta_saved_state *saved_state,
struct radv_cmd_buffer *cmd_buffer);
void radv_meta_resolve_compute_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *src_image,
VkImageLayout src_image_layout,
struct radv_image *dest_image,
VkImageLayout dest_image_layout,
uint32_t region_count,
const VkImageResolve *regions);
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,543 @@
#include "radv_meta.h"
#include "nir/nir_builder.h"
#include "sid.h"
#include "radv_cs.h"
static nir_shader *
build_buffer_fill_shader(struct radv_device *dev)
{
nir_builder b;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_COMPUTE, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_buffer_fill");
b.shader->info.cs.local_size[0] = 64;
b.shader->info.cs.local_size[1] = 1;
b.shader->info.cs.local_size[2] = 1;
nir_ssa_def *invoc_id = nir_load_system_value(&b, nir_intrinsic_load_local_invocation_id, 0);
nir_ssa_def *wg_id = nir_load_system_value(&b, nir_intrinsic_load_work_group_id, 0);
nir_ssa_def *block_size = nir_imm_ivec4(&b,
b.shader->info.cs.local_size[0],
b.shader->info.cs.local_size[1],
b.shader->info.cs.local_size[2], 0);
nir_ssa_def *global_id = nir_iadd(&b, nir_imul(&b, wg_id, block_size), invoc_id);
nir_ssa_def *offset = nir_imul(&b, global_id, nir_imm_int(&b, 16));
offset = nir_swizzle(&b, offset, (unsigned[]) {0, 0, 0, 0}, 1, false);
nir_intrinsic_instr *dst_buf = nir_intrinsic_instr_create(b.shader,
nir_intrinsic_vulkan_resource_index);
dst_buf->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
nir_intrinsic_set_desc_set(dst_buf, 0);
nir_intrinsic_set_binding(dst_buf, 0);
nir_ssa_dest_init(&dst_buf->instr, &dst_buf->dest, 1, 32, NULL);
nir_builder_instr_insert(&b, &dst_buf->instr);
nir_intrinsic_instr *load = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
load->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
load->num_components = 1;
nir_ssa_dest_init(&load->instr, &load->dest, 1, 32, "fill_value");
nir_builder_instr_insert(&b, &load->instr);
nir_ssa_def *swizzled_load = nir_swizzle(&b, &load->dest.ssa, (unsigned[]) { 0, 0, 0, 0}, 4, false);
nir_intrinsic_instr *store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_store_ssbo);
store->src[0] = nir_src_for_ssa(swizzled_load);
store->src[1] = nir_src_for_ssa(&dst_buf->dest.ssa);
store->src[2] = nir_src_for_ssa(offset);
nir_intrinsic_set_write_mask(store, 0xf);
store->num_components = 4;
nir_builder_instr_insert(&b, &store->instr);
return b.shader;
}
static nir_shader *
build_buffer_copy_shader(struct radv_device *dev)
{
nir_builder b;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_COMPUTE, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_buffer_copy");
b.shader->info.cs.local_size[0] = 64;
b.shader->info.cs.local_size[1] = 1;
b.shader->info.cs.local_size[2] = 1;
nir_ssa_def *invoc_id = nir_load_system_value(&b, nir_intrinsic_load_local_invocation_id, 0);
nir_ssa_def *wg_id = nir_load_system_value(&b, nir_intrinsic_load_work_group_id, 0);
nir_ssa_def *block_size = nir_imm_ivec4(&b,
b.shader->info.cs.local_size[0],
b.shader->info.cs.local_size[1],
b.shader->info.cs.local_size[2], 0);
nir_ssa_def *global_id = nir_iadd(&b, nir_imul(&b, wg_id, block_size), invoc_id);
nir_ssa_def *offset = nir_imul(&b, global_id, nir_imm_int(&b, 16));
offset = nir_swizzle(&b, offset, (unsigned[]) {0, 0, 0, 0}, 1, false);
nir_intrinsic_instr *dst_buf = nir_intrinsic_instr_create(b.shader,
nir_intrinsic_vulkan_resource_index);
dst_buf->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
nir_intrinsic_set_desc_set(dst_buf, 0);
nir_intrinsic_set_binding(dst_buf, 0);
nir_ssa_dest_init(&dst_buf->instr, &dst_buf->dest, 1, 32, NULL);
nir_builder_instr_insert(&b, &dst_buf->instr);
nir_intrinsic_instr *src_buf = nir_intrinsic_instr_create(b.shader,
nir_intrinsic_vulkan_resource_index);
src_buf->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
nir_intrinsic_set_desc_set(src_buf, 0);
nir_intrinsic_set_binding(src_buf, 1);
nir_ssa_dest_init(&src_buf->instr, &src_buf->dest, 1, 32, NULL);
nir_builder_instr_insert(&b, &src_buf->instr);
nir_intrinsic_instr *load = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_ssbo);
load->src[0] = nir_src_for_ssa(&src_buf->dest.ssa);
load->src[1] = nir_src_for_ssa(offset);
nir_ssa_dest_init(&load->instr, &load->dest, 4, 32, NULL);
load->num_components = 4;
nir_builder_instr_insert(&b, &load->instr);
nir_intrinsic_instr *store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_store_ssbo);
store->src[0] = nir_src_for_ssa(&load->dest.ssa);
store->src[1] = nir_src_for_ssa(&dst_buf->dest.ssa);
store->src[2] = nir_src_for_ssa(offset);
nir_intrinsic_set_write_mask(store, 0xf);
store->num_components = 4;
nir_builder_instr_insert(&b, &store->instr);
return b.shader;
}
VkResult radv_device_init_meta_buffer_state(struct radv_device *device)
{
VkResult result;
struct radv_shader_module fill_cs = { .nir = NULL };
struct radv_shader_module copy_cs = { .nir = NULL };
zero(device->meta_state.buffer);
fill_cs.nir = build_buffer_fill_shader(device);
copy_cs.nir = build_buffer_copy_shader(device);
VkDescriptorSetLayoutCreateInfo fill_ds_create_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 1,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
}
};
result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
&fill_ds_create_info,
&device->meta_state.alloc,
&device->meta_state.buffer.fill_ds_layout);
if (result != VK_SUCCESS)
goto fail;
VkDescriptorSetLayoutCreateInfo copy_ds_create_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 2,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
}
};
result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
&copy_ds_create_info,
&device->meta_state.alloc,
&device->meta_state.buffer.copy_ds_layout);
if (result != VK_SUCCESS)
goto fail;
VkPipelineLayoutCreateInfo fill_pl_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &device->meta_state.buffer.fill_ds_layout,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &(VkPushConstantRange){VK_SHADER_STAGE_COMPUTE_BIT, 0, 4},
};
result = radv_CreatePipelineLayout(radv_device_to_handle(device),
&fill_pl_create_info,
&device->meta_state.alloc,
&device->meta_state.buffer.fill_p_layout);
if (result != VK_SUCCESS)
goto fail;
VkPipelineLayoutCreateInfo copy_pl_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &device->meta_state.buffer.copy_ds_layout,
.pushConstantRangeCount = 0,
};
result = radv_CreatePipelineLayout(radv_device_to_handle(device),
&copy_pl_create_info,
&device->meta_state.alloc,
&device->meta_state.buffer.copy_p_layout);
if (result != VK_SUCCESS)
goto fail;
VkPipelineShaderStageCreateInfo fill_pipeline_shader_stage = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = radv_shader_module_to_handle(&fill_cs),
.pName = "main",
.pSpecializationInfo = NULL,
};
VkComputePipelineCreateInfo fill_vk_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.stage = fill_pipeline_shader_stage,
.flags = 0,
.layout = device->meta_state.buffer.fill_p_layout,
};
result = radv_CreateComputePipelines(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
1, &fill_vk_pipeline_info, NULL,
&device->meta_state.buffer.fill_pipeline);
if (result != VK_SUCCESS)
goto fail;
VkPipelineShaderStageCreateInfo copy_pipeline_shader_stage = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = radv_shader_module_to_handle(&copy_cs),
.pName = "main",
.pSpecializationInfo = NULL,
};
VkComputePipelineCreateInfo copy_vk_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.stage = copy_pipeline_shader_stage,
.flags = 0,
.layout = device->meta_state.buffer.copy_p_layout,
};
result = radv_CreateComputePipelines(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
1, &copy_vk_pipeline_info, NULL,
&device->meta_state.buffer.copy_pipeline);
if (result != VK_SUCCESS)
goto fail;
ralloc_free(fill_cs.nir);
ralloc_free(copy_cs.nir);
return VK_SUCCESS;
fail:
radv_device_finish_meta_buffer_state(device);
ralloc_free(fill_cs.nir);
ralloc_free(copy_cs.nir);
return result;
}
void radv_device_finish_meta_buffer_state(struct radv_device *device)
{
if (device->meta_state.buffer.copy_pipeline)
radv_DestroyPipeline(radv_device_to_handle(device),
device->meta_state.buffer.copy_pipeline,
&device->meta_state.alloc);
if (device->meta_state.buffer.fill_pipeline)
radv_DestroyPipeline(radv_device_to_handle(device),
device->meta_state.buffer.fill_pipeline,
&device->meta_state.alloc);
if (device->meta_state.buffer.copy_p_layout)
radv_DestroyPipelineLayout(radv_device_to_handle(device),
device->meta_state.buffer.copy_p_layout,
&device->meta_state.alloc);
if (device->meta_state.buffer.fill_p_layout)
radv_DestroyPipelineLayout(radv_device_to_handle(device),
device->meta_state.buffer.fill_p_layout,
&device->meta_state.alloc);
if (device->meta_state.buffer.copy_ds_layout)
radv_DestroyDescriptorSetLayout(radv_device_to_handle(device),
device->meta_state.buffer.copy_ds_layout,
&device->meta_state.alloc);
if (device->meta_state.buffer.fill_ds_layout)
radv_DestroyDescriptorSetLayout(radv_device_to_handle(device),
device->meta_state.buffer.fill_ds_layout,
&device->meta_state.alloc);
}
static void fill_buffer_shader(struct radv_cmd_buffer *cmd_buffer,
struct radeon_winsys_bo *bo,
uint64_t offset, uint64_t size, uint32_t value)
{
struct radv_device *device = cmd_buffer->device;
uint64_t block_count = round_up_u64(size, 1024);
struct radv_meta_saved_compute_state saved_state;
VkDescriptorSet ds;
radv_meta_save_compute(&saved_state, cmd_buffer, 4);
radv_temp_descriptor_set_create(device, cmd_buffer,
device->meta_state.buffer.fill_ds_layout,
&ds);
struct radv_buffer dst_buffer = {
.bo = bo,
.offset = offset,
.size = size
};
radv_UpdateDescriptorSets(radv_device_to_handle(device),
1, /* writeCount */
(VkWriteDescriptorSet[]) {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = ds,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &(VkDescriptorBufferInfo) {
.buffer = radv_buffer_to_handle(&dst_buffer),
.offset = 0,
.range = size
}
}
}, 0, NULL);
radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.buffer.fill_pipeline);
radv_CmdBindDescriptorSets(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.buffer.fill_p_layout, 0, 1,
&ds, 0, NULL);
radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
device->meta_state.buffer.fill_p_layout,
VK_SHADER_STAGE_COMPUTE_BIT, 0, 4,
&value);
radv_CmdDispatch(radv_cmd_buffer_to_handle(cmd_buffer), block_count, 1, 1);
radv_temp_descriptor_set_destroy(device, ds);
radv_meta_restore_compute(&saved_state, cmd_buffer, 4);
}
static void copy_buffer_shader(struct radv_cmd_buffer *cmd_buffer,
struct radeon_winsys_bo *src_bo,
struct radeon_winsys_bo *dst_bo,
uint64_t src_offset, uint64_t dst_offset,
uint64_t size)
{
struct radv_device *device = cmd_buffer->device;
uint64_t block_count = round_up_u64(size, 1024);
struct radv_meta_saved_compute_state saved_state;
VkDescriptorSet ds;
radv_meta_save_compute(&saved_state, cmd_buffer, 0);
radv_temp_descriptor_set_create(device, cmd_buffer,
device->meta_state.buffer.copy_ds_layout,
&ds);
struct radv_buffer dst_buffer = {
.bo = dst_bo,
.offset = dst_offset,
.size = size
};
struct radv_buffer src_buffer = {
.bo = src_bo,
.offset = src_offset,
.size = size
};
radv_UpdateDescriptorSets(radv_device_to_handle(device),
2, /* writeCount */
(VkWriteDescriptorSet[]) {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = ds,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &(VkDescriptorBufferInfo) {
.buffer = radv_buffer_to_handle(&dst_buffer),
.offset = 0,
.range = size
}
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = ds,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.pBufferInfo = &(VkDescriptorBufferInfo) {
.buffer = radv_buffer_to_handle(&src_buffer),
.offset = 0,
.range = size
}
}
}, 0, NULL);
radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.buffer.copy_pipeline);
radv_CmdBindDescriptorSets(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.buffer.copy_p_layout, 0, 1,
&ds, 0, NULL);
radv_CmdDispatch(radv_cmd_buffer_to_handle(cmd_buffer), block_count, 1, 1);
radv_temp_descriptor_set_destroy(device, ds);
radv_meta_restore_compute(&saved_state, cmd_buffer, 0);
}
void radv_fill_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radeon_winsys_bo *bo,
uint64_t offset, uint64_t size, uint32_t value)
{
assert(!(offset & 3));
assert(!(size & 3));
if (size >= 4096)
fill_buffer_shader(cmd_buffer, bo, offset, size, value);
else if (size) {
uint64_t va = cmd_buffer->device->ws->buffer_get_va(bo);
va += offset;
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, bo, 8);
si_cp_dma_clear_buffer(cmd_buffer, va, size, value);
}
}
static
void radv_copy_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radeon_winsys_bo *src_bo,
struct radeon_winsys_bo *dst_bo,
uint64_t src_offset, uint64_t dst_offset,
uint64_t size)
{
if (size >= 4096 && !(size & 3) && !(src_offset & 3) && !(dst_offset & 3))
copy_buffer_shader(cmd_buffer, src_bo, dst_bo,
src_offset, dst_offset, size);
else if (size) {
uint64_t src_va = cmd_buffer->device->ws->buffer_get_va(src_bo);
uint64_t dst_va = cmd_buffer->device->ws->buffer_get_va(dst_bo);
src_va += src_offset;
dst_va += dst_offset;
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, src_bo, 8);
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, dst_bo, 8);
si_cp_dma_buffer_copy(cmd_buffer, src_va, dst_va, size);
}
}
void radv_CmdFillBuffer(
VkCommandBuffer commandBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize fillSize,
uint32_t data)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_buffer, dst_buffer, dstBuffer);
if (fillSize == VK_WHOLE_SIZE)
fillSize = (dst_buffer->size - dstOffset) & ~3ull;
radv_fill_buffer(cmd_buffer, dst_buffer->bo, dst_buffer->offset + dstOffset,
fillSize, data);
}
void radv_CmdCopyBuffer(
VkCommandBuffer commandBuffer,
VkBuffer srcBuffer,
VkBuffer destBuffer,
uint32_t regionCount,
const VkBufferCopy* pRegions)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_buffer, src_buffer, srcBuffer);
RADV_FROM_HANDLE(radv_buffer, dest_buffer, destBuffer);
for (unsigned r = 0; r < regionCount; r++) {
uint64_t src_offset = src_buffer->offset + pRegions[r].srcOffset;
uint64_t dest_offset = dest_buffer->offset + pRegions[r].dstOffset;
uint64_t copy_size = pRegions[r].size;
radv_copy_buffer(cmd_buffer, src_buffer->bo, dest_buffer->bo,
src_offset, dest_offset, copy_size);
}
}
void radv_CmdUpdateBuffer(
VkCommandBuffer commandBuffer,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize dataSize,
const uint32_t* pData)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_buffer, dst_buffer, dstBuffer);
uint64_t words = dataSize / 4;
uint64_t va = cmd_buffer->device->ws->buffer_get_va(dst_buffer->bo);
va += dstOffset + dst_buffer->offset;
assert(!(dataSize & 3));
assert(!(va & 3));
if (dataSize < 4096) {
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, dst_buffer->bo, 8);
radeon_check_space(cmd_buffer->device->ws, cmd_buffer->cs, words + 4);
radeon_emit(cmd_buffer->cs, PKT3(PKT3_WRITE_DATA, 2 + words, 0));
radeon_emit(cmd_buffer->cs, S_370_DST_SEL(V_370_MEMORY_SYNC) |
S_370_WR_CONFIRM(1) |
S_370_ENGINE_SEL(V_370_ME));
radeon_emit(cmd_buffer->cs, va);
radeon_emit(cmd_buffer->cs, va >> 32);
radeon_emit_array(cmd_buffer->cs, pData, words);
} else {
uint32_t buf_offset;
radv_cmd_buffer_upload_data(cmd_buffer, dataSize, 32, pData, &buf_offset);
radv_copy_buffer(cmd_buffer, cmd_buffer->upload.upload_bo, dst_buffer->bo,
buf_offset, dstOffset + dst_buffer->offset, dataSize);
}
}

View File

@ -0,0 +1,396 @@
#include "radv_meta.h"
#include "nir/nir_builder.h"
static nir_shader *
build_nir_itob_compute_shader(struct radv_device *dev)
{
nir_builder b;
const struct glsl_type *sampler_type = glsl_sampler_type(GLSL_SAMPLER_DIM_2D,
false,
false,
GLSL_TYPE_FLOAT);
const struct glsl_type *img_type = glsl_sampler_type(GLSL_SAMPLER_DIM_BUF,
false,
false,
GLSL_TYPE_FLOAT);
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_COMPUTE, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_itob_cs");
b.shader->info.cs.local_size[0] = 16;
b.shader->info.cs.local_size[1] = 16;
b.shader->info.cs.local_size[2] = 1;
nir_variable *input_img = nir_variable_create(b.shader, nir_var_uniform,
sampler_type, "s_tex");
input_img->data.descriptor_set = 0;
input_img->data.binding = 0;
nir_variable *output_img = nir_variable_create(b.shader, nir_var_uniform,
img_type, "out_img");
output_img->data.descriptor_set = 0;
output_img->data.binding = 1;
nir_ssa_def *invoc_id = nir_load_system_value(&b, nir_intrinsic_load_local_invocation_id, 0);
nir_ssa_def *wg_id = nir_load_system_value(&b, nir_intrinsic_load_work_group_id, 0);
nir_ssa_def *block_size = nir_imm_ivec4(&b,
b.shader->info.cs.local_size[0],
b.shader->info.cs.local_size[1],
b.shader->info.cs.local_size[2], 0);
nir_ssa_def *global_id = nir_iadd(&b, nir_imul(&b, wg_id, block_size), invoc_id);
nir_intrinsic_instr *offset = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
offset->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
offset->num_components = 2;
nir_ssa_dest_init(&offset->instr, &offset->dest, 2, 32, "offset");
nir_builder_instr_insert(&b, &offset->instr);
nir_intrinsic_instr *stride = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
stride->src[0] = nir_src_for_ssa(nir_imm_int(&b, 8));
stride->num_components = 1;
nir_ssa_dest_init(&stride->instr, &stride->dest, 1, 32, "stride");
nir_builder_instr_insert(&b, &stride->instr);
nir_ssa_def *img_coord = nir_iadd(&b, global_id, &offset->dest.ssa);
nir_tex_instr *tex = nir_tex_instr_create(b.shader, 2);
tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
tex->op = nir_texop_txf;
tex->src[0].src_type = nir_tex_src_coord;
tex->src[0].src = nir_src_for_ssa(img_coord);
tex->src[1].src_type = nir_tex_src_lod;
tex->src[1].src = nir_src_for_ssa(nir_imm_int(&b, 0));
tex->dest_type = nir_type_float;
tex->is_array = false;
tex->coord_components = 2;
tex->texture = nir_deref_var_create(tex, input_img);
tex->sampler = NULL;
nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
nir_builder_instr_insert(&b, &tex->instr);
nir_ssa_def *pos_x = nir_channel(&b, global_id, 0);
nir_ssa_def *pos_y = nir_channel(&b, global_id, 1);
nir_ssa_def *tmp = nir_imul(&b, pos_y, &stride->dest.ssa);
tmp = nir_iadd(&b, tmp, pos_x);
nir_ssa_def *coord = nir_vec4(&b, tmp, tmp, tmp, tmp);
nir_ssa_def *outval = &tex->dest.ssa;
nir_intrinsic_instr *store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_image_store);
store->src[0] = nir_src_for_ssa(coord);
store->src[1] = nir_src_for_ssa(nir_ssa_undef(&b, 1, 32));
store->src[2] = nir_src_for_ssa(outval);
store->variables[0] = nir_deref_var_create(store, output_img);
nir_builder_instr_insert(&b, &store->instr);
return b.shader;
}
/* Image to buffer - don't write use image accessors */
static VkResult
radv_device_init_meta_itob_state(struct radv_device *device)
{
VkResult result;
struct radv_shader_module cs = { .nir = NULL };
zero(device->meta_state.itob);
cs.nir = build_nir_itob_compute_shader(device);
/*
* two descriptors one for the image being sampled
* one for the buffer being written.
*/
VkDescriptorSetLayoutCreateInfo ds_create_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 2,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
}
};
result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
&ds_create_info,
&device->meta_state.alloc,
&device->meta_state.itob.img_ds_layout);
if (result != VK_SUCCESS)
goto fail;
VkPipelineLayoutCreateInfo pl_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &device->meta_state.itob.img_ds_layout,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &(VkPushConstantRange){VK_SHADER_STAGE_COMPUTE_BIT, 0, 12},
};
result = radv_CreatePipelineLayout(radv_device_to_handle(device),
&pl_create_info,
&device->meta_state.alloc,
&device->meta_state.itob.img_p_layout);
if (result != VK_SUCCESS)
goto fail;
/* compute shader */
VkPipelineShaderStageCreateInfo pipeline_shader_stage = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = radv_shader_module_to_handle(&cs),
.pName = "main",
.pSpecializationInfo = NULL,
};
VkComputePipelineCreateInfo vk_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.stage = pipeline_shader_stage,
.flags = 0,
.layout = device->meta_state.itob.img_p_layout,
};
result = radv_CreateComputePipelines(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
1, &vk_pipeline_info, NULL,
&device->meta_state.itob.pipeline);
if (result != VK_SUCCESS)
goto fail;
ralloc_free(cs.nir);
return VK_SUCCESS;
fail:
ralloc_free(cs.nir);
return result;
}
static void
radv_device_finish_meta_itob_state(struct radv_device *device)
{
if (device->meta_state.itob.img_p_layout) {
radv_DestroyPipelineLayout(radv_device_to_handle(device),
device->meta_state.itob.img_p_layout,
&device->meta_state.alloc);
}
if (device->meta_state.itob.img_ds_layout) {
radv_DestroyDescriptorSetLayout(radv_device_to_handle(device),
device->meta_state.itob.img_ds_layout,
&device->meta_state.alloc);
}
if (device->meta_state.itob.pipeline) {
radv_DestroyPipeline(radv_device_to_handle(device),
device->meta_state.itob.pipeline,
&device->meta_state.alloc);
}
}
void
radv_device_finish_meta_bufimage_state(struct radv_device *device)
{
radv_device_finish_meta_itob_state(device);
}
VkResult
radv_device_init_meta_bufimage_state(struct radv_device *device)
{
VkResult result;
result = radv_device_init_meta_itob_state(device);
if (result != VK_SUCCESS)
return result;
return VK_SUCCESS;
}
void
radv_meta_begin_bufimage(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_compute_state *save)
{
radv_meta_save_compute(save, cmd_buffer, 12);
}
void
radv_meta_end_bufimage(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_saved_compute_state *save)
{
radv_meta_restore_compute(save, cmd_buffer, 12);
}
static void
create_iview(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_surf *surf,
VkImageUsageFlags usage,
struct radv_image_view *iview)
{
radv_image_view_init(iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = radv_image_to_handle(surf->image),
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = surf->format,
.subresourceRange = {
.aspectMask = surf->aspect_mask,
.baseMipLevel = surf->level,
.levelCount = 1,
.baseArrayLayer = surf->layer,
.layerCount = 1
},
}, cmd_buffer, usage);
}
static void
create_bview(struct radv_cmd_buffer *cmd_buffer,
struct radv_buffer *buffer,
unsigned offset,
VkFormat format,
struct radv_buffer_view *bview)
{
radv_buffer_view_init(bview, cmd_buffer->device,
&(VkBufferViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO,
.flags = 0,
.buffer = radv_buffer_to_handle(buffer),
.format = format,
.offset = offset,
.range = VK_WHOLE_SIZE,
}, cmd_buffer);
}
struct itob_temps {
struct radv_image_view src_iview;
struct radv_buffer_view dst_bview;
VkDescriptorSet set;
};
static void
itob_bind_src_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_surf *src,
struct radv_meta_blit2d_rect *rect,
struct itob_temps *tmp)
{
create_iview(cmd_buffer, src, VK_IMAGE_USAGE_SAMPLED_BIT, &tmp->src_iview);
}
static void
itob_bind_dst_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_buffer *dst,
struct radv_meta_blit2d_rect *rect,
struct itob_temps *tmp)
{
create_bview(cmd_buffer, dst->buffer, dst->offset, dst->format, &tmp->dst_bview);
}
static void
itob_bind_descriptors(struct radv_cmd_buffer *cmd_buffer,
struct itob_temps *tmp)
{
struct radv_device *device = cmd_buffer->device;
VkDevice vk_device = radv_device_to_handle(cmd_buffer->device);
radv_temp_descriptor_set_create(device, cmd_buffer,
device->meta_state.itob.img_ds_layout,
&tmp->set);
radv_UpdateDescriptorSets(vk_device,
2, /* writeCount */
(VkWriteDescriptorSet[]) {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = tmp->set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = (VkDescriptorImageInfo[]) {
{
.sampler = NULL,
.imageView = radv_image_view_to_handle(&tmp->src_iview),
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
},
}
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = tmp->set,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
.pTexelBufferView = (VkBufferView[]) { radv_buffer_view_to_handle(&tmp->dst_bview) },
}
}, 0, NULL);
radv_CmdBindDescriptorSets(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.itob.img_p_layout, 0, 1,
&tmp->set, 0, NULL);
}
static void
itob_unbind_src_image(struct radv_cmd_buffer *cmd_buffer,
struct itob_temps *temps)
{
}
static void
bind_pipeline(struct radv_cmd_buffer *cmd_buffer)
{
VkPipeline pipeline =
cmd_buffer->device->meta_state.itob.pipeline;
if (cmd_buffer->state.compute_pipeline != radv_pipeline_from_handle(pipeline)) {
radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
}
}
void
radv_meta_image_to_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radv_meta_blit2d_surf *src,
struct radv_meta_blit2d_buffer *dst,
unsigned num_rects,
struct radv_meta_blit2d_rect *rects)
{
struct radv_device *device = cmd_buffer->device;
for (unsigned r = 0; r < num_rects; ++r) {
struct itob_temps temps;
itob_bind_src_image(cmd_buffer, src, &rects[r], &temps);
itob_bind_dst_buffer(cmd_buffer, dst, &rects[r], &temps);
itob_bind_descriptors(cmd_buffer, &temps);
bind_pipeline(cmd_buffer);
unsigned push_constants[3] = {
rects[r].src_x,
rects[r].src_y,
dst->pitch
};
radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
device->meta_state.itob.img_p_layout,
VK_SHADER_STAGE_COMPUTE_BIT, 0, 12,
push_constants);
radv_unaligned_dispatch(cmd_buffer, rects[r].width, rects[r].height, 1);
radv_temp_descriptor_set_destroy(cmd_buffer->device, temps.set);
itob_unbind_src_image(cmd_buffer, &temps);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,399 @@
/*
* Copyright © 2016 Intel 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 "radv_meta.h"
#include "vk_format.h"
static VkExtent3D
meta_image_block_size(const struct radv_image *image)
{
const struct vk_format_description *desc = vk_format_description(image->vk_format);
return (VkExtent3D) { desc->block.width, desc->block.height, 1 };
}
/* Returns the user-provided VkBufferImageCopy::imageExtent in units of
* elements rather than texels. One element equals one texel or one block
* if Image is uncompressed or compressed, respectively.
*/
static struct VkExtent3D
meta_region_extent_el(const struct radv_image *image,
const struct VkExtent3D *extent)
{
const VkExtent3D block = meta_image_block_size(image);
return radv_sanitize_image_extent(image->type, (VkExtent3D) {
.width = DIV_ROUND_UP(extent->width , block.width),
.height = DIV_ROUND_UP(extent->height, block.height),
.depth = DIV_ROUND_UP(extent->depth , block.depth),
});
}
/* Returns the user-provided VkBufferImageCopy::imageOffset in units of
* elements rather than texels. One element equals one texel or one block
* if Image is uncompressed or compressed, respectively.
*/
static struct VkOffset3D
meta_region_offset_el(const struct radv_image *image,
const struct VkOffset3D *offset)
{
const VkExtent3D block = meta_image_block_size(image);
return radv_sanitize_image_offset(image->type, (VkOffset3D) {
.x = offset->x / block.width,
.y = offset->y / block.height,
.z = offset->z / block.depth,
});
}
static VkFormat
vk_format_for_size(int bs)
{
switch (bs) {
case 1: return VK_FORMAT_R8_UINT;
case 2: return VK_FORMAT_R8G8_UINT;
case 4: return VK_FORMAT_R8G8B8A8_UINT;
case 8: return VK_FORMAT_R16G16B16A16_UINT;
case 16: return VK_FORMAT_R32G32B32A32_UINT;
default:
unreachable("Invalid format block size");
}
}
static struct radv_meta_blit2d_surf
blit_surf_for_image_level_layer(struct radv_image* image, VkImageAspectFlags aspectMask,
int level, int layer)
{
VkFormat format = image->vk_format;
if (aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
format = vk_format_depth_only(format);
else if (aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
format = vk_format_stencil_only(format);
if (!image->surface.dcc_size)
format = vk_format_for_size(vk_format_get_blocksize(format));
return (struct radv_meta_blit2d_surf) {
.format = format,
.bs = vk_format_get_blocksize(format),
.level = level,
.layer = layer,
.image = image,
.aspect_mask = aspectMask,
};
}
static void
meta_copy_buffer_to_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_buffer* buffer,
struct radv_image* image,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
struct radv_meta_saved_state saved_state;
/* The Vulkan 1.0 spec says "dstImage must have a sample count equal to
* VK_SAMPLE_COUNT_1_BIT."
*/
assert(image->samples == 1);
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
for (unsigned r = 0; r < regionCount; r++) {
/**
* From the Vulkan 1.0.6 spec: 18.3 Copying Data Between Images
* extent is the size in texels of the source image to copy in width,
* height and depth. 1D images use only x and width. 2D images use x, y,
* width and height. 3D images use x, y, z, width, height and depth.
*
*
* Also, convert the offsets and extent from units of texels to units of
* blocks - which is the highest resolution accessible in this command.
*/
const VkOffset3D img_offset_el =
meta_region_offset_el(image, &pRegions[r].imageOffset);
const VkExtent3D bufferExtent = {
.width = pRegions[r].bufferRowLength ?
pRegions[r].bufferRowLength : pRegions[r].imageExtent.width,
.height = pRegions[r].bufferImageHeight ?
pRegions[r].bufferImageHeight : pRegions[r].imageExtent.height,
};
const VkExtent3D buf_extent_el =
meta_region_extent_el(image, &bufferExtent);
/* Start creating blit rect */
const VkExtent3D img_extent_el =
meta_region_extent_el(image, &pRegions[r].imageExtent);
struct radv_meta_blit2d_rect rect = {
.width = img_extent_el.width,
.height = img_extent_el.height,
};
/* Create blit surfaces */
struct radv_meta_blit2d_surf img_bsurf =
blit_surf_for_image_level_layer(image,
pRegions[r].imageSubresource.aspectMask,
pRegions[r].imageSubresource.mipLevel,
pRegions[r].imageSubresource.baseArrayLayer);
struct radv_meta_blit2d_buffer buf_bsurf = {
.bs = img_bsurf.bs,
.format = img_bsurf.format,
.buffer = buffer,
.offset = pRegions[r].bufferOffset,
.pitch = buf_extent_el.width,
};
/* Loop through each 3D or array slice */
unsigned num_slices_3d = img_extent_el.depth;
unsigned num_slices_array = pRegions[r].imageSubresource.layerCount;
unsigned slice_3d = 0;
unsigned slice_array = 0;
while (slice_3d < num_slices_3d && slice_array < num_slices_array) {
rect.dst_x = img_offset_el.x;
rect.dst_y = img_offset_el.y;
/* Perform Blit */
radv_meta_blit2d(cmd_buffer, NULL, &buf_bsurf, &img_bsurf, 1, &rect);
/* Once we've done the blit, all of the actual information about
* the image is embedded in the command buffer so we can just
* increment the offset directly in the image effectively
* re-binding it to different backing memory.
*/
buf_bsurf.offset += buf_extent_el.width *
buf_extent_el.height * buf_bsurf.bs;
img_bsurf.layer++;
if (image->type == VK_IMAGE_TYPE_3D)
slice_3d++;
else
slice_array++;
}
}
radv_meta_restore(&saved_state, cmd_buffer);
}
void radv_CmdCopyBufferToImage(
VkCommandBuffer commandBuffer,
VkBuffer srcBuffer,
VkImage destImage,
VkImageLayout destImageLayout,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_image, dest_image, destImage);
RADV_FROM_HANDLE(radv_buffer, src_buffer, srcBuffer);
meta_copy_buffer_to_image(cmd_buffer, src_buffer, dest_image,
regionCount, pRegions);
}
static void
meta_copy_image_to_buffer(struct radv_cmd_buffer *cmd_buffer,
struct radv_buffer* buffer,
struct radv_image* image,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
struct radv_meta_saved_compute_state saved_state;
radv_meta_begin_bufimage(cmd_buffer, &saved_state);
for (unsigned r = 0; r < regionCount; r++) {
/**
* From the Vulkan 1.0.6 spec: 18.3 Copying Data Between Images
* extent is the size in texels of the source image to copy in width,
* height and depth. 1D images use only x and width. 2D images use x, y,
* width and height. 3D images use x, y, z, width, height and depth.
*
*
* Also, convert the offsets and extent from units of texels to units of
* blocks - which is the highest resolution accessible in this command.
*/
const VkOffset3D img_offset_el =
meta_region_offset_el(image, &pRegions[r].imageOffset);
const VkExtent3D bufferExtent = {
.width = pRegions[r].bufferRowLength ?
pRegions[r].bufferRowLength : pRegions[r].imageExtent.width,
.height = pRegions[r].bufferImageHeight ?
pRegions[r].bufferImageHeight : pRegions[r].imageExtent.height,
};
const VkExtent3D buf_extent_el =
meta_region_extent_el(image, &bufferExtent);
/* Start creating blit rect */
const VkExtent3D img_extent_el =
meta_region_extent_el(image, &pRegions[r].imageExtent);
struct radv_meta_blit2d_rect rect = {
.width = img_extent_el.width,
.height = img_extent_el.height,
};
/* Create blit surfaces */
struct radv_meta_blit2d_surf img_info =
blit_surf_for_image_level_layer(image,
pRegions[r].imageSubresource.aspectMask,
pRegions[r].imageSubresource.mipLevel,
pRegions[r].imageSubresource.baseArrayLayer);
struct radv_meta_blit2d_buffer buf_info = {
.bs = img_info.bs,
.format = img_info.format,
.buffer = buffer,
.offset = pRegions[r].bufferOffset,
.pitch = buf_extent_el.width,
};
/* Loop through each 3D or array slice */
unsigned num_slices_3d = img_extent_el.depth;
unsigned num_slices_array = pRegions[r].imageSubresource.layerCount;
unsigned slice_3d = 0;
unsigned slice_array = 0;
while (slice_3d < num_slices_3d && slice_array < num_slices_array) {
rect.src_x = img_offset_el.x;
rect.src_y = img_offset_el.y;
/* Perform Blit */
radv_meta_image_to_buffer(cmd_buffer, &img_info, &buf_info, 1, &rect);
buf_info.offset += buf_extent_el.width *
buf_extent_el.height * buf_info.bs;
img_info.layer++;
if (image->type == VK_IMAGE_TYPE_3D)
slice_3d++;
else
slice_array++;
}
}
radv_meta_end_bufimage(cmd_buffer, &saved_state);
}
void radv_CmdCopyImageToBuffer(
VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkBuffer destBuffer,
uint32_t regionCount,
const VkBufferImageCopy* pRegions)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_image, src_image, srcImage);
RADV_FROM_HANDLE(radv_buffer, dst_buffer, destBuffer);
meta_copy_image_to_buffer(cmd_buffer, dst_buffer, src_image,
regionCount, pRegions);
}
void radv_CmdCopyImage(
VkCommandBuffer commandBuffer,
VkImage srcImage,
VkImageLayout srcImageLayout,
VkImage destImage,
VkImageLayout destImageLayout,
uint32_t regionCount,
const VkImageCopy* pRegions)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_image, src_image, srcImage);
RADV_FROM_HANDLE(radv_image, dest_image, destImage);
struct radv_meta_saved_state saved_state;
/* From the Vulkan 1.0 spec:
*
* vkCmdCopyImage can be used to copy image data between multisample
* images, but both images must have the same number of samples.
*/
assert(src_image->samples == dest_image->samples);
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
for (unsigned r = 0; r < regionCount; r++) {
assert(pRegions[r].srcSubresource.aspectMask ==
pRegions[r].dstSubresource.aspectMask);
/* Create blit surfaces */
struct radv_meta_blit2d_surf b_src =
blit_surf_for_image_level_layer(src_image,
pRegions[r].srcSubresource.aspectMask,
pRegions[r].srcSubresource.mipLevel,
pRegions[r].srcSubresource.baseArrayLayer);
struct radv_meta_blit2d_surf b_dst =
blit_surf_for_image_level_layer(dest_image,
pRegions[r].dstSubresource.aspectMask,
pRegions[r].dstSubresource.mipLevel,
pRegions[r].dstSubresource.baseArrayLayer);
/* for DCC */
b_src.format = b_dst.format;
/**
* From the Vulkan 1.0.6 spec: 18.4 Copying Data Between Buffers and Images
* imageExtent is the size in texels of the image to copy in width, height
* and depth. 1D images use only x and width. 2D images use x, y, width
* and height. 3D images use x, y, z, width, height and depth.
*
* Also, convert the offsets and extent from units of texels to units of
* blocks - which is the highest resolution accessible in this command.
*/
const VkOffset3D dst_offset_el =
meta_region_offset_el(dest_image, &pRegions[r].dstOffset);
const VkOffset3D src_offset_el =
meta_region_offset_el(src_image, &pRegions[r].srcOffset);
const VkExtent3D img_extent_el =
meta_region_extent_el(src_image, &pRegions[r].extent);
/* Start creating blit rect */
struct radv_meta_blit2d_rect rect = {
.width = img_extent_el.width,
.height = img_extent_el.height,
};
/* Loop through each 3D or array slice */
unsigned num_slices_3d = img_extent_el.depth;
unsigned num_slices_array = pRegions[r].dstSubresource.layerCount;
unsigned slice_3d = 0;
unsigned slice_array = 0;
while (slice_3d < num_slices_3d && slice_array < num_slices_array) {
/* Finish creating blit rect */
rect.dst_x = dst_offset_el.x;
rect.dst_y = dst_offset_el.y;
rect.src_x = src_offset_el.x;
rect.src_y = src_offset_el.y;
/* Perform Blit */
radv_meta_blit2d(cmd_buffer, &b_src, NULL, &b_dst, 1, &rect);
b_src.layer++;
b_dst.layer++;
if (dest_image->type == VK_IMAGE_TYPE_3D)
slice_3d++;
else
slice_array++;
}
}
radv_meta_restore(&saved_state, cmd_buffer);
}

View File

@ -0,0 +1,463 @@
/*
* Copyright © 2016 Intel 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 <assert.h>
#include <stdbool.h>
#include "radv_meta.h"
#include "radv_private.h"
#include "nir/nir_builder.h"
#include "sid.h"
/**
* Vertex attributes used by all pipelines.
*/
struct vertex_attrs {
float position[2]; /**< 3DPRIM_RECTLIST */
};
/* passthrough vertex shader */
static nir_shader *
build_nir_vs(void)
{
const struct glsl_type *vec4 = glsl_vec4_type();
nir_builder b;
nir_variable *a_position;
nir_variable *v_position;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_depth_decomp_vs");
a_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"a_position");
a_position->data.location = VERT_ATTRIB_GENERIC0;
v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"gl_Position");
v_position->data.location = VARYING_SLOT_POS;
nir_copy_var(&b, v_position, a_position);
return b.shader;
}
/* simple passthrough shader */
static nir_shader *
build_nir_fs(void)
{
nir_builder b;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
b.shader->info.name = ralloc_asprintf(b.shader,
"meta_depth_decomp_noop_fs");
return b.shader;
}
static VkResult
create_pass(struct radv_device *device)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
VkAttachmentDescription attachment;
attachment.format = VK_FORMAT_UNDEFINED;
attachment.samples = 1;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.initialLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
result = radv_CreateRenderPass(device_h,
&(VkRenderPassCreateInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = &attachment,
.subpassCount = 1,
.pSubpasses = &(VkSubpassDescription) {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.colorAttachmentCount = 0,
.pColorAttachments = NULL,
.pResolveAttachments = NULL,
.pDepthStencilAttachment = &(VkAttachmentReference) {
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL,
},
.preserveAttachmentCount = 0,
.pPreserveAttachments = NULL,
},
.dependencyCount = 0,
},
alloc,
&device->meta_state.depth_decomp.pass);
return result;
}
static VkResult
create_pipeline(struct radv_device *device,
VkShaderModule vs_module_h)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
struct radv_shader_module fs_module = {
.nir = build_nir_fs(),
};
if (!fs_module.nir) {
/* XXX: Need more accurate error */
result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto cleanup;
}
const VkGraphicsPipelineCreateInfo pipeline_create_info = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = (VkPipelineShaderStageCreateInfo[]) {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vs_module_h,
.pName = "main",
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = radv_shader_module_to_handle(&fs_module),
.pName = "main",
},
},
.pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
{
.binding = 0,
.stride = sizeof(struct vertex_attrs),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
},
},
.vertexAttributeDescriptionCount = 1,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
{
/* Position */
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct vertex_attrs, position),
},
},
},
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
.primitiveRestartEnable = false,
},
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 0,
.scissorCount = 0,
},
.pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
},
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = 1,
.sampleShadingEnable = false,
.pSampleMask = NULL,
.alphaToCoverageEnable = false,
.alphaToOneEnable = false,
},
.pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = false,
.attachmentCount = 0,
.pAttachments = NULL,
},
.pDepthStencilState = &(VkPipelineDepthStencilStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
.depthTestEnable = false,
.depthWriteEnable = false,
.depthBoundsTestEnable = false,
.stencilTestEnable = false,
},
.pDynamicState = NULL,
.renderPass = device->meta_state.depth_decomp.pass,
.subpass = 0,
};
result = radv_graphics_pipeline_create(device_h,
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&pipeline_create_info,
&(struct radv_graphics_pipeline_create_info) {
.use_rectlist = true,
.db_flush_depth_inplace = true,
.db_flush_stencil_inplace = true,
},
&device->meta_state.alloc,
&device->meta_state.depth_decomp.decompress_pipeline);
if (result != VK_SUCCESS)
goto cleanup;
result = radv_graphics_pipeline_create(device_h,
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&pipeline_create_info,
&(struct radv_graphics_pipeline_create_info) {
.use_rectlist = true,
.db_flush_depth_inplace = true,
.db_flush_stencil_inplace = true,
.db_resummarize = true,
},
&device->meta_state.alloc,
&device->meta_state.depth_decomp.resummarize_pipeline);
if (result != VK_SUCCESS)
goto cleanup;
goto cleanup;
cleanup:
ralloc_free(fs_module.nir);
return result;
}
void
radv_device_finish_meta_depth_decomp_state(struct radv_device *device)
{
struct radv_meta_state *state = &device->meta_state;
VkDevice device_h = radv_device_to_handle(device);
VkRenderPass pass_h = device->meta_state.depth_decomp.pass;
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
if (pass_h)
RADV_CALL(DestroyRenderPass)(device_h, pass_h,
&device->meta_state.alloc);
VkPipeline pipeline_h = state->depth_decomp.decompress_pipeline;
if (pipeline_h) {
RADV_CALL(DestroyPipeline)(device_h, pipeline_h, alloc);
}
pipeline_h = state->depth_decomp.resummarize_pipeline;
if (pipeline_h) {
RADV_CALL(DestroyPipeline)(device_h, pipeline_h, alloc);
}
}
VkResult
radv_device_init_meta_depth_decomp_state(struct radv_device *device)
{
VkResult res = VK_SUCCESS;
zero(device->meta_state.depth_decomp);
struct radv_shader_module vs_module = { .nir = build_nir_vs() };
if (!vs_module.nir) {
/* XXX: Need more accurate error */
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto fail;
}
res = create_pass(device);
if (res != VK_SUCCESS)
goto fail;
VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
res = create_pipeline(device, vs_module_h);
if (res != VK_SUCCESS)
goto fail;
goto cleanup;
fail:
radv_device_finish_meta_depth_decomp_state(device);
cleanup:
ralloc_free(vs_module.nir);
return res;
}
static void
emit_depth_decomp(struct radv_cmd_buffer *cmd_buffer,
const VkOffset2D *dest_offset,
const VkExtent2D *depth_decomp_extent,
VkPipeline pipeline_h)
{
struct radv_device *device = cmd_buffer->device;
VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
uint32_t offset;
const struct vertex_attrs vertex_data[3] = {
{
.position = {
dest_offset->x,
dest_offset->y,
},
},
{
.position = {
dest_offset->x,
dest_offset->y + depth_decomp_extent->height,
},
},
{
.position = {
dest_offset->x + depth_decomp_extent->width,
dest_offset->y,
},
},
};
radv_cmd_buffer_upload_data(cmd_buffer, sizeof(vertex_data), 16, vertex_data, &offset);
struct radv_buffer vertex_buffer = {
.device = device,
.size = sizeof(vertex_data),
.bo = cmd_buffer->upload.upload_bo,
.offset = offset,
};
VkBuffer vertex_buffer_h = radv_buffer_to_handle(&vertex_buffer);
radv_CmdBindVertexBuffers(cmd_buffer_h,
/*firstBinding*/ 0,
/*bindingCount*/ 1,
(VkBuffer[]) { vertex_buffer_h },
(VkDeviceSize[]) { 0 });
RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h);
if (cmd_buffer->state.pipeline != pipeline) {
radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_h);
}
RADV_CALL(CmdDraw)(cmd_buffer_h, 3, 1, 0, 0);
}
static void radv_process_depth_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image,
VkImageSubresourceRange *subresourceRange,
VkPipeline pipeline_h)
{
struct radv_meta_saved_state saved_state;
struct radv_meta_saved_pass_state saved_pass_state;
VkDevice device_h = radv_device_to_handle(cmd_buffer->device);
VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
uint32_t width = radv_minify(image->extent.width,
subresourceRange->baseMipLevel);
uint32_t height = radv_minify(image->extent.height,
subresourceRange->baseMipLevel);
if (!image->htile.size)
return;
radv_meta_save_pass(&saved_pass_state, cmd_buffer);
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
for (uint32_t layer = 0; layer < subresourceRange->layerCount; layer++) {
struct radv_image_view iview;
radv_image_view_init(&iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = radv_image_to_handle(image),
.format = image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
.baseMipLevel = subresourceRange->baseMipLevel,
.levelCount = 1,
.baseArrayLayer = subresourceRange->baseArrayLayer + layer,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT);
VkFramebuffer fb_h;
radv_CreateFramebuffer(device_h,
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = (VkImageView[]) {
radv_image_view_to_handle(&iview)
},
.width = width,
.height = height,
.layers = 1
},
&cmd_buffer->pool->alloc,
&fb_h);
RADV_CALL(CmdBeginRenderPass)(cmd_buffer_h,
&(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = cmd_buffer->device->meta_state.depth_decomp.pass,
.framebuffer = fb_h,
.renderArea = {
.offset = {
0,
0,
},
.extent = {
width,
height,
}
},
.clearValueCount = 0,
.pClearValues = NULL,
},
VK_SUBPASS_CONTENTS_INLINE);
emit_depth_decomp(cmd_buffer, &(VkOffset2D){0, 0 }, &(VkExtent2D){width, height}, pipeline_h);
RADV_CALL(CmdEndRenderPass)(cmd_buffer_h);
radv_DestroyFramebuffer(device_h, fb_h,
&cmd_buffer->pool->alloc);
}
radv_meta_restore(&saved_state, cmd_buffer);
radv_meta_restore_pass(&saved_pass_state, cmd_buffer);
}
void radv_decompress_depth_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image,
VkImageSubresourceRange *subresourceRange)
{
radv_process_depth_image_inplace(cmd_buffer, image, subresourceRange,
cmd_buffer->device->meta_state.depth_decomp.decompress_pipeline);
}
void radv_resummarize_depth_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image,
VkImageSubresourceRange *subresourceRange)
{
radv_process_depth_image_inplace(cmd_buffer, image, subresourceRange,
cmd_buffer->device->meta_state.depth_decomp.resummarize_pipeline);
}

View File

@ -0,0 +1,536 @@
/*
* Copyright © 2016 Intel 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 <assert.h>
#include <stdbool.h>
#include "radv_meta.h"
#include "radv_private.h"
#include "nir/nir_builder.h"
#include "sid.h"
/**
* Vertex attributes used by all pipelines.
*/
struct vertex_attrs {
float position[2]; /**< 3DPRIM_RECTLIST */
float tex_position[2];
};
/* passthrough vertex shader */
static nir_shader *
build_nir_vs(void)
{
const struct glsl_type *vec4 = glsl_vec4_type();
nir_builder b;
nir_variable *a_position;
nir_variable *v_position;
nir_variable *a_tex_position;
nir_variable *v_tex_position;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_fast_clear_vs");
a_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"a_position");
a_position->data.location = VERT_ATTRIB_GENERIC0;
v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"gl_Position");
v_position->data.location = VARYING_SLOT_POS;
a_tex_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"a_tex_position");
a_tex_position->data.location = VERT_ATTRIB_GENERIC1;
v_tex_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"v_tex_position");
v_tex_position->data.location = VARYING_SLOT_VAR0;
nir_copy_var(&b, v_position, a_position);
nir_copy_var(&b, v_tex_position, a_tex_position);
return b.shader;
}
/* simple passthrough shader */
static nir_shader *
build_nir_fs(void)
{
const struct glsl_type *vec4 = glsl_vec4_type();
nir_builder b;
nir_variable *v_tex_position; /* vec4, varying texture coordinate */
nir_variable *f_color; /* vec4, fragment output color */
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
b.shader->info.name = ralloc_asprintf(b.shader,
"meta_fast_clear_fs");
v_tex_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"v_tex_position");
v_tex_position->data.location = VARYING_SLOT_VAR0;
f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"f_color");
f_color->data.location = FRAG_RESULT_DATA0;
nir_copy_var(&b, f_color, v_tex_position);
return b.shader;
}
static VkResult
create_pass(struct radv_device *device)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
VkAttachmentDescription attachment;
attachment.format = VK_FORMAT_UNDEFINED;
attachment.samples = 1;
attachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachment.initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachment.finalLayout = VK_IMAGE_LAYOUT_GENERAL;
result = radv_CreateRenderPass(device_h,
&(VkRenderPassCreateInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = &attachment,
.subpassCount = 1,
.pSubpasses = &(VkSubpassDescription) {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.colorAttachmentCount = 1,
.pColorAttachments = (VkAttachmentReference[]) {
{
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_GENERAL,
},
},
.pResolveAttachments = NULL,
.pDepthStencilAttachment = &(VkAttachmentReference) {
.attachment = VK_ATTACHMENT_UNUSED,
},
.preserveAttachmentCount = 0,
.pPreserveAttachments = NULL,
},
.dependencyCount = 0,
},
alloc,
&device->meta_state.fast_clear_flush.pass);
return result;
}
static VkResult
create_pipeline(struct radv_device *device,
VkShaderModule vs_module_h)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
struct radv_shader_module fs_module = {
.nir = build_nir_fs(),
};
if (!fs_module.nir) {
/* XXX: Need more accurate error */
result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto cleanup;
}
const VkPipelineShaderStageCreateInfo stages[2] = {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vs_module_h,
.pName = "main",
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = radv_shader_module_to_handle(&fs_module),
.pName = "main",
},
};
const VkPipelineVertexInputStateCreateInfo vi_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
{
.binding = 0,
.stride = sizeof(struct vertex_attrs),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
},
},
.vertexAttributeDescriptionCount = 2,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
{
/* Position */
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct vertex_attrs, position),
},
{
/* Texture Coordinate */
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct vertex_attrs, tex_position),
},
}
};
const VkPipelineInputAssemblyStateCreateInfo ia_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
.primitiveRestartEnable = false,
};
const VkPipelineColorBlendStateCreateInfo blend_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = false,
.attachmentCount = 1,
.pAttachments = (VkPipelineColorBlendAttachmentState []) {
{
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT,
},
}
};
const VkPipelineRasterizationStateCreateInfo rs_state = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
};
result = radv_graphics_pipeline_create(device_h,
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&(VkGraphicsPipelineCreateInfo) {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = stages,
.pVertexInputState = &vi_state,
.pInputAssemblyState = &ia_state,
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 0,
.scissorCount = 0,
},
.pRasterizationState = &rs_state,
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = 1,
.sampleShadingEnable = false,
.pSampleMask = NULL,
.alphaToCoverageEnable = false,
.alphaToOneEnable = false,
},
.pColorBlendState = &blend_state,
.pDynamicState = NULL,
.renderPass = device->meta_state.fast_clear_flush.pass,
.subpass = 0,
},
&(struct radv_graphics_pipeline_create_info) {
.use_rectlist = true,
.custom_blend_mode = V_028808_CB_ELIMINATE_FAST_CLEAR,
},
&device->meta_state.alloc,
&device->meta_state.fast_clear_flush.cmask_eliminate_pipeline);
if (result != VK_SUCCESS)
goto cleanup;
result = radv_graphics_pipeline_create(device_h,
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&(VkGraphicsPipelineCreateInfo) {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = stages,
.pVertexInputState = &vi_state,
.pInputAssemblyState = &ia_state,
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 0,
.scissorCount = 0,
},
.pRasterizationState = &rs_state,
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = 1,
.sampleShadingEnable = false,
.pSampleMask = NULL,
.alphaToCoverageEnable = false,
.alphaToOneEnable = false,
},
.pColorBlendState = &blend_state,
.pDynamicState = NULL,
.renderPass = device->meta_state.fast_clear_flush.pass,
.subpass = 0,
},
&(struct radv_graphics_pipeline_create_info) {
.use_rectlist = true,
.custom_blend_mode = V_028808_CB_FMASK_DECOMPRESS,
},
&device->meta_state.alloc,
&device->meta_state.fast_clear_flush.fmask_decompress_pipeline);
if (result != VK_SUCCESS)
goto cleanup_cmask;
goto cleanup;
cleanup_cmask:
RADV_CALL(DestroyPipeline)(device_h, device->meta_state.fast_clear_flush.cmask_eliminate_pipeline, &device->meta_state.alloc);
cleanup:
ralloc_free(fs_module.nir);
return result;
}
void
radv_device_finish_meta_fast_clear_flush_state(struct radv_device *device)
{
struct radv_meta_state *state = &device->meta_state;
VkDevice device_h = radv_device_to_handle(device);
VkRenderPass pass_h = device->meta_state.fast_clear_flush.pass;
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
if (pass_h)
RADV_CALL(DestroyRenderPass)(device_h, pass_h,
&device->meta_state.alloc);
VkPipeline pipeline_h = state->fast_clear_flush.cmask_eliminate_pipeline;
if (pipeline_h) {
RADV_CALL(DestroyPipeline)(device_h, pipeline_h, alloc);
}
pipeline_h = state->fast_clear_flush.fmask_decompress_pipeline;
if (pipeline_h) {
RADV_CALL(DestroyPipeline)(device_h, pipeline_h, alloc);
}
}
VkResult
radv_device_init_meta_fast_clear_flush_state(struct radv_device *device)
{
VkResult res = VK_SUCCESS;
zero(device->meta_state.fast_clear_flush);
struct radv_shader_module vs_module = { .nir = build_nir_vs() };
if (!vs_module.nir) {
/* XXX: Need more accurate error */
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto fail;
}
res = create_pass(device);
if (res != VK_SUCCESS)
goto fail;
VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
res = create_pipeline(device, vs_module_h);
if (res != VK_SUCCESS)
goto fail;
goto cleanup;
fail:
radv_device_finish_meta_fast_clear_flush_state(device);
cleanup:
ralloc_free(vs_module.nir);
return res;
}
static void
emit_fast_clear_flush(struct radv_cmd_buffer *cmd_buffer,
const VkExtent2D *resolve_extent,
bool fmask_decompress)
{
struct radv_device *device = cmd_buffer->device;
VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
uint32_t offset;
const struct vertex_attrs vertex_data[3] = {
{
.position = {
0,
0,
},
.tex_position = {
0,
0,
},
},
{
.position = {
0,
resolve_extent->height,
},
.tex_position = {
0,
resolve_extent->height,
},
},
{
.position = {
resolve_extent->width,
0,
},
.tex_position = {
resolve_extent->width,
0,
},
},
};
cmd_buffer->state.flush_bits |= (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
RADV_CMD_FLAG_FLUSH_AND_INV_CB_META);
radv_cmd_buffer_upload_data(cmd_buffer, sizeof(vertex_data), 16, vertex_data, &offset);
struct radv_buffer vertex_buffer = {
.device = device,
.size = sizeof(vertex_data),
.bo = cmd_buffer->upload.upload_bo,
.offset = offset,
};
VkBuffer vertex_buffer_h = radv_buffer_to_handle(&vertex_buffer);
radv_CmdBindVertexBuffers(cmd_buffer_h,
/*firstBinding*/ 0,
/*bindingCount*/ 1,
(VkBuffer[]) { vertex_buffer_h },
(VkDeviceSize[]) { 0 });
VkPipeline pipeline_h;
if (fmask_decompress)
pipeline_h = device->meta_state.fast_clear_flush.fmask_decompress_pipeline;
else
pipeline_h = device->meta_state.fast_clear_flush.cmask_eliminate_pipeline;
RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h);
if (cmd_buffer->state.pipeline != pipeline) {
radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_h);
}
RADV_CALL(CmdDraw)(cmd_buffer_h, 3, 1, 0, 0);
cmd_buffer->state.flush_bits |= (RADV_CMD_FLAG_FLUSH_AND_INV_CB |
RADV_CMD_FLAG_FLUSH_AND_INV_CB_META);
si_emit_cache_flush(cmd_buffer);
}
/**
*/
void
radv_fast_clear_flush_image_inplace(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *image)
{
struct radv_meta_saved_state saved_state;
struct radv_meta_saved_pass_state saved_pass_state;
VkDevice device_h = radv_device_to_handle(cmd_buffer->device);
VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
if (!image->cmask.size)
return;
if (!cmd_buffer->device->allow_fast_clears)
return;
radv_meta_save_pass(&saved_pass_state, cmd_buffer);
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
struct radv_image_view iview;
radv_image_view_init(&iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = radv_image_to_handle(image),
.format = image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
VkFramebuffer fb_h;
radv_CreateFramebuffer(device_h,
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.attachmentCount = 1,
.pAttachments = (VkImageView[]) {
radv_image_view_to_handle(&iview)
},
.width = image->extent.width,
.height = image->extent.height,
.layers = 1
},
&cmd_buffer->pool->alloc,
&fb_h);
RADV_CALL(CmdBeginRenderPass)(cmd_buffer_h,
&(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = cmd_buffer->device->meta_state.fast_clear_flush.pass,
.framebuffer = fb_h,
.renderArea = {
.offset = {
0,
0,
},
.extent = {
image->extent.width,
image->extent.height,
}
},
.clearValueCount = 0,
.pClearValues = NULL,
},
VK_SUBPASS_CONTENTS_INLINE);
emit_fast_clear_flush(cmd_buffer,
&(VkExtent2D) { image->extent.width, image->extent.height },
image->fmask.size > 0);
RADV_CALL(CmdEndRenderPass)(cmd_buffer_h);
radv_DestroyFramebuffer(device_h, fb_h,
&cmd_buffer->pool->alloc);
radv_meta_restore(&saved_state, cmd_buffer);
radv_meta_restore_pass(&saved_pass_state, cmd_buffer);
}

View File

@ -0,0 +1,670 @@
/*
* Copyright © 2016 Intel 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 <assert.h>
#include <stdbool.h>
#include "radv_meta.h"
#include "radv_private.h"
#include "nir/nir_builder.h"
#include "sid.h"
/**
* Vertex attributes used by all pipelines.
*/
struct vertex_attrs {
float position[2]; /**< 3DPRIM_RECTLIST */
float tex_position[2];
};
/* passthrough vertex shader */
static nir_shader *
build_nir_vs(void)
{
const struct glsl_type *vec4 = glsl_vec4_type();
nir_builder b;
nir_variable *a_position;
nir_variable *v_position;
nir_variable *a_tex_position;
nir_variable *v_tex_position;
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_VERTEX, NULL);
b.shader->info.name = ralloc_strdup(b.shader, "meta_resolve_vs");
a_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"a_position");
a_position->data.location = VERT_ATTRIB_GENERIC0;
v_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"gl_Position");
v_position->data.location = VARYING_SLOT_POS;
a_tex_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"a_tex_position");
a_tex_position->data.location = VERT_ATTRIB_GENERIC1;
v_tex_position = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"v_tex_position");
v_tex_position->data.location = VARYING_SLOT_VAR0;
nir_copy_var(&b, v_position, a_position);
nir_copy_var(&b, v_tex_position, a_tex_position);
return b.shader;
}
/* simple passthrough shader */
static nir_shader *
build_nir_fs(void)
{
const struct glsl_type *vec4 = glsl_vec4_type();
nir_builder b;
nir_variable *v_tex_position; /* vec4, varying texture coordinate */
nir_variable *f_color; /* vec4, fragment output color */
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, NULL);
b.shader->info.name = ralloc_asprintf(b.shader,
"meta_resolve_fs");
v_tex_position = nir_variable_create(b.shader, nir_var_shader_in, vec4,
"v_tex_position");
v_tex_position->data.location = VARYING_SLOT_VAR0;
f_color = nir_variable_create(b.shader, nir_var_shader_out, vec4,
"f_color");
f_color->data.location = FRAG_RESULT_DATA0;
nir_copy_var(&b, f_color, v_tex_position);
return b.shader;
}
static VkResult
create_pass(struct radv_device *device)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
VkAttachmentDescription attachments[2];
int i;
for (i = 0; i < 2; i++) {
attachments[i].format = VK_FORMAT_UNDEFINED;
attachments[i].samples = 1;
attachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
attachments[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
attachments[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
attachments[i].finalLayout = VK_IMAGE_LAYOUT_GENERAL;
}
result = radv_CreateRenderPass(device_h,
&(VkRenderPassCreateInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 2,
.pAttachments = attachments,
.subpassCount = 1,
.pSubpasses = &(VkSubpassDescription) {
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.inputAttachmentCount = 0,
.colorAttachmentCount = 2,
.pColorAttachments = (VkAttachmentReference[]) {
{
.attachment = 0,
.layout = VK_IMAGE_LAYOUT_GENERAL,
},
{
.attachment = 1,
.layout = VK_IMAGE_LAYOUT_GENERAL,
},
},
.pResolveAttachments = NULL,
.pDepthStencilAttachment = &(VkAttachmentReference) {
.attachment = VK_ATTACHMENT_UNUSED,
},
.preserveAttachmentCount = 0,
.pPreserveAttachments = NULL,
},
.dependencyCount = 0,
},
alloc,
&device->meta_state.resolve.pass);
return result;
}
static VkResult
create_pipeline(struct radv_device *device,
VkShaderModule vs_module_h)
{
VkResult result;
VkDevice device_h = radv_device_to_handle(device);
struct radv_shader_module fs_module = {
.nir = build_nir_fs(),
};
if (!fs_module.nir) {
/* XXX: Need more accurate error */
result = VK_ERROR_OUT_OF_HOST_MEMORY;
goto cleanup;
}
result = radv_graphics_pipeline_create(device_h,
radv_pipeline_cache_to_handle(&device->meta_state.cache),
&(VkGraphicsPipelineCreateInfo) {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.stageCount = 2,
.pStages = (VkPipelineShaderStageCreateInfo[]) {
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = vs_module_h,
.pName = "main",
},
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = radv_shader_module_to_handle(&fs_module),
.pName = "main",
},
},
.pVertexInputState = &(VkPipelineVertexInputStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = (VkVertexInputBindingDescription[]) {
{
.binding = 0,
.stride = sizeof(struct vertex_attrs),
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX
},
},
.vertexAttributeDescriptionCount = 2,
.pVertexAttributeDescriptions = (VkVertexInputAttributeDescription[]) {
{
/* Position */
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct vertex_attrs, position),
},
{
/* Texture Coordinate */
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(struct vertex_attrs, tex_position),
},
},
},
.pInputAssemblyState = &(VkPipelineInputAssemblyStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
.primitiveRestartEnable = false,
},
.pViewportState = &(VkPipelineViewportStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 0,
.scissorCount = 0,
},
.pRasterizationState = &(VkPipelineRasterizationStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = VK_POLYGON_MODE_FILL,
.cullMode = VK_CULL_MODE_NONE,
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
},
.pMultisampleState = &(VkPipelineMultisampleStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
.rasterizationSamples = 1,
.sampleShadingEnable = false,
.pSampleMask = NULL,
.alphaToCoverageEnable = false,
.alphaToOneEnable = false,
},
.pColorBlendState = &(VkPipelineColorBlendStateCreateInfo) {
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = false,
.attachmentCount = 2,
.pAttachments = (VkPipelineColorBlendAttachmentState []) {
{
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT |
VK_COLOR_COMPONENT_G_BIT |
VK_COLOR_COMPONENT_B_BIT |
VK_COLOR_COMPONENT_A_BIT,
},
{
.colorWriteMask = 0,
}
},
},
.pDynamicState = NULL,
.renderPass = device->meta_state.resolve.pass,
.subpass = 0,
},
&(struct radv_graphics_pipeline_create_info) {
.use_rectlist = true,
.custom_blend_mode = V_028808_CB_RESOLVE,
},
&device->meta_state.alloc,
&device->meta_state.resolve.pipeline);
if (result != VK_SUCCESS)
goto cleanup;
goto cleanup;
cleanup:
ralloc_free(fs_module.nir);
return result;
}
void
radv_device_finish_meta_resolve_state(struct radv_device *device)
{
struct radv_meta_state *state = &device->meta_state;
VkDevice device_h = radv_device_to_handle(device);
VkRenderPass pass_h = device->meta_state.resolve.pass;
const VkAllocationCallbacks *alloc = &device->meta_state.alloc;
if (pass_h)
RADV_CALL(DestroyRenderPass)(device_h, pass_h,
&device->meta_state.alloc);
VkPipeline pipeline_h = state->resolve.pipeline;
if (pipeline_h) {
RADV_CALL(DestroyPipeline)(device_h, pipeline_h, alloc);
}
}
VkResult
radv_device_init_meta_resolve_state(struct radv_device *device)
{
VkResult res = VK_SUCCESS;
zero(device->meta_state.resolve);
struct radv_shader_module vs_module = { .nir = build_nir_vs() };
if (!vs_module.nir) {
/* XXX: Need more accurate error */
res = VK_ERROR_OUT_OF_HOST_MEMORY;
goto fail;
}
res = create_pass(device);
if (res != VK_SUCCESS)
goto fail;
VkShaderModule vs_module_h = radv_shader_module_to_handle(&vs_module);
res = create_pipeline(device, vs_module_h);
if (res != VK_SUCCESS)
goto fail;
goto cleanup;
fail:
radv_device_finish_meta_resolve_state(device);
cleanup:
ralloc_free(vs_module.nir);
return res;
}
static void
emit_resolve(struct radv_cmd_buffer *cmd_buffer,
const VkOffset2D *src_offset,
const VkOffset2D *dest_offset,
const VkExtent2D *resolve_extent)
{
struct radv_device *device = cmd_buffer->device;
VkCommandBuffer cmd_buffer_h = radv_cmd_buffer_to_handle(cmd_buffer);
uint32_t offset;
const struct vertex_attrs vertex_data[3] = {
{
.position = {
dest_offset->x,
dest_offset->y,
},
.tex_position = {
src_offset->x,
src_offset->y,
},
},
{
.position = {
dest_offset->x,
dest_offset->y + resolve_extent->height,
},
.tex_position = {
src_offset->x,
src_offset->y + resolve_extent->height,
},
},
{
.position = {
dest_offset->x + resolve_extent->width,
dest_offset->y,
},
.tex_position = {
src_offset->x + resolve_extent->width,
src_offset->y,
},
},
};
cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
radv_cmd_buffer_upload_data(cmd_buffer, sizeof(vertex_data), 16, vertex_data, &offset);
struct radv_buffer vertex_buffer = {
.device = device,
.size = sizeof(vertex_data),
.bo = cmd_buffer->upload.upload_bo,
.offset = offset,
};
VkBuffer vertex_buffer_h = radv_buffer_to_handle(&vertex_buffer);
radv_CmdBindVertexBuffers(cmd_buffer_h,
/*firstBinding*/ 0,
/*bindingCount*/ 1,
(VkBuffer[]) { vertex_buffer_h },
(VkDeviceSize[]) { 0 });
VkPipeline pipeline_h = device->meta_state.resolve.pipeline;
RADV_FROM_HANDLE(radv_pipeline, pipeline, pipeline_h);
if (cmd_buffer->state.pipeline != pipeline) {
radv_CmdBindPipeline(cmd_buffer_h, VK_PIPELINE_BIND_POINT_GRAPHICS,
pipeline_h);
}
RADV_CALL(CmdDraw)(cmd_buffer_h, 3, 1, 0, 0);
cmd_buffer->state.flush_bits |= RADV_CMD_FLAG_FLUSH_AND_INV_CB;
si_emit_cache_flush(cmd_buffer);
}
void radv_CmdResolveImage(
VkCommandBuffer cmd_buffer_h,
VkImage src_image_h,
VkImageLayout src_image_layout,
VkImage dest_image_h,
VkImageLayout dest_image_layout,
uint32_t region_count,
const VkImageResolve* regions)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, cmd_buffer_h);
RADV_FROM_HANDLE(radv_image, src_image, src_image_h);
RADV_FROM_HANDLE(radv_image, dest_image, dest_image_h);
struct radv_device *device = cmd_buffer->device;
struct radv_meta_saved_state saved_state;
VkDevice device_h = radv_device_to_handle(device);
bool use_compute_resolve = false;
/* we can use the hw resolve only for single full resolves */
if (region_count == 1) {
if (regions[0].srcOffset.x ||
regions[0].srcOffset.y ||
regions[0].srcOffset.z)
use_compute_resolve = true;
if (regions[0].dstOffset.x ||
regions[0].dstOffset.y ||
regions[0].dstOffset.z)
use_compute_resolve = true;
if (regions[0].extent.width != src_image->extent.width ||
regions[0].extent.height != src_image->extent.height ||
regions[0].extent.depth != src_image->extent.depth)
use_compute_resolve = true;
} else
use_compute_resolve = true;
if (use_compute_resolve) {
radv_meta_resolve_compute_image(cmd_buffer,
src_image,
src_image_layout,
dest_image,
dest_image_layout,
region_count, regions);
return;
}
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
assert(src_image->samples > 1);
assert(dest_image->samples == 1);
if (src_image->samples >= 16) {
/* See commit aa3f9aaf31e9056a255f9e0472ebdfdaa60abe54 for the
* glBlitFramebuffer workaround for samples >= 16.
*/
radv_finishme("vkCmdResolveImage: need interpolation workaround when "
"samples >= 16");
}
if (src_image->array_size > 1)
radv_finishme("vkCmdResolveImage: multisample array images");
for (uint32_t r = 0; r < region_count; ++r) {
const VkImageResolve *region = &regions[r];
/* From the Vulkan 1.0 spec:
*
* - The aspectMask member of srcSubresource and dstSubresource must
* only contain VK_IMAGE_ASPECT_COLOR_BIT
*
* - The layerCount member of srcSubresource and dstSubresource must
* match
*/
assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
assert(region->srcSubresource.layerCount ==
region->dstSubresource.layerCount);
const uint32_t src_base_layer =
radv_meta_get_iview_layer(src_image, &region->srcSubresource,
&region->srcOffset);
const uint32_t dest_base_layer =
radv_meta_get_iview_layer(dest_image, &region->dstSubresource,
&region->dstOffset);
/**
* From Vulkan 1.0.6 spec: 18.6 Resolving Multisample Images
*
* extent is the size in texels of the source image to resolve in width,
* height and depth. 1D images use only x and width. 2D images use x, y,
* width and height. 3D images use x, y, z, width, height and depth.
*
* srcOffset and dstOffset select the initial x, y, and z offsets in
* texels of the sub-regions of the source and destination image data.
* extent is the size in texels of the source image to resolve in width,
* height and depth. 1D images use only x and width. 2D images use x, y,
* width and height. 3D images use x, y, z, width, height and depth.
*/
const struct VkExtent3D extent =
radv_sanitize_image_extent(src_image->type, region->extent);
const struct VkOffset3D srcOffset =
radv_sanitize_image_offset(src_image->type, region->srcOffset);
const struct VkOffset3D dstOffset =
radv_sanitize_image_offset(dest_image->type, region->dstOffset);
for (uint32_t layer = 0; layer < region->srcSubresource.layerCount;
++layer) {
struct radv_image_view src_iview;
radv_image_view_init(&src_iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = src_image_h,
.viewType = radv_meta_get_view_type(src_image),
.format = src_image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = region->srcSubresource.mipLevel,
.levelCount = 1,
.baseArrayLayer = src_base_layer + layer,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_SAMPLED_BIT);
struct radv_image_view dest_iview;
radv_image_view_init(&dest_iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = dest_image_h,
.viewType = radv_meta_get_view_type(dest_image),
.format = dest_image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = region->dstSubresource.mipLevel,
.levelCount = 1,
.baseArrayLayer = dest_base_layer + layer,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
VkFramebuffer fb_h;
radv_CreateFramebuffer(device_h,
&(VkFramebufferCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
.attachmentCount = 2,
.pAttachments = (VkImageView[]) {
radv_image_view_to_handle(&src_iview),
radv_image_view_to_handle(&dest_iview),
},
.width = radv_minify(dest_image->extent.width,
region->dstSubresource.mipLevel),
.height = radv_minify(dest_image->extent.height,
region->dstSubresource.mipLevel),
.layers = 1
},
&cmd_buffer->pool->alloc,
&fb_h);
RADV_CALL(CmdBeginRenderPass)(cmd_buffer_h,
&(VkRenderPassBeginInfo) {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = device->meta_state.resolve.pass,
.framebuffer = fb_h,
.renderArea = {
.offset = {
dstOffset.x,
dstOffset.y,
},
.extent = {
extent.width,
extent.height,
}
},
.clearValueCount = 0,
.pClearValues = NULL,
},
VK_SUBPASS_CONTENTS_INLINE);
emit_resolve(cmd_buffer,
&(VkOffset2D) {
.x = srcOffset.x,
.y = srcOffset.y,
},
&(VkOffset2D) {
.x = dstOffset.x,
.y = dstOffset.y,
},
&(VkExtent2D) {
.width = extent.width,
.height = extent.height,
});
RADV_CALL(CmdEndRenderPass)(cmd_buffer_h);
radv_DestroyFramebuffer(device_h, fb_h,
&cmd_buffer->pool->alloc);
}
}
radv_meta_restore(&saved_state, cmd_buffer);
}
/**
* Emit any needed resolves for the current subpass.
*/
void
radv_cmd_buffer_resolve_subpass(struct radv_cmd_buffer *cmd_buffer)
{
struct radv_framebuffer *fb = cmd_buffer->state.framebuffer;
const struct radv_subpass *subpass = cmd_buffer->state.subpass;
struct radv_meta_saved_state saved_state;
/* FINISHME(perf): Skip clears for resolve attachments.
*
* From the Vulkan 1.0 spec:
*
* If the first use of an attachment in a render pass is as a resolve
* attachment, then the loadOp is effectively ignored as the resolve is
* guaranteed to overwrite all pixels in the render area.
*/
if (!subpass->has_resolve)
return;
radv_meta_save_graphics_reset_vport_scissor(&saved_state, cmd_buffer);
for (uint32_t i = 0; i < subpass->color_count; ++i) {
VkAttachmentReference src_att = subpass->color_attachments[i];
VkAttachmentReference dest_att = subpass->resolve_attachments[i];
struct radv_image *dst_img = cmd_buffer->state.framebuffer->attachments[dest_att.attachment].attachment->image;
if (dest_att.attachment == VK_ATTACHMENT_UNUSED)
continue;
if (dst_img->surface.dcc_size) {
radv_initialize_dcc(cmd_buffer, dst_img, 0xffffffff);
cmd_buffer->state.attachments[dest_att.attachment].current_layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
struct radv_subpass resolve_subpass = {
.color_count = 2,
.color_attachments = (VkAttachmentReference[]) { src_att, dest_att },
.depth_stencil_attachment = { .attachment = VK_ATTACHMENT_UNUSED },
};
radv_cmd_buffer_set_subpass(cmd_buffer, &resolve_subpass, false);
/* Subpass resolves must respect the render area. We can ignore the
* render area here because vkCmdBeginRenderPass set the render area
* with 3DSTATE_DRAWING_RECTANGLE.
*
* XXX(chadv): Does the hardware really respect
* 3DSTATE_DRAWING_RECTANGLE when draing a 3DPRIM_RECTLIST?
*/
emit_resolve(cmd_buffer,
&(VkOffset2D) { 0, 0 },
&(VkOffset2D) { 0, 0 },
&(VkExtent2D) { fb->width, fb->height });
}
cmd_buffer->state.subpass = subpass;
radv_meta_restore(&saved_state, cmd_buffer);
}

View File

@ -0,0 +1,461 @@
/*
* Copyright © 2016 Dave Airlie
*
* 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 <assert.h>
#include <stdbool.h>
#include "radv_meta.h"
#include "radv_private.h"
#include "nir/nir_builder.h"
#include "sid.h"
#include "vk_format.h"
static nir_shader *
build_resolve_compute_shader(struct radv_device *dev, bool is_integer, int samples)
{
nir_builder b;
char name[64];
nir_if *outer_if = NULL;
const struct glsl_type *sampler_type = glsl_sampler_type(GLSL_SAMPLER_DIM_MS,
false,
false,
GLSL_TYPE_FLOAT);
const struct glsl_type *img_type = glsl_sampler_type(GLSL_SAMPLER_DIM_2D,
false,
false,
GLSL_TYPE_FLOAT);
snprintf(name, 64, "meta_resolve_cs-%d-%s", samples, is_integer ? "int" : "float");
nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_COMPUTE, NULL);
b.shader->info.name = ralloc_strdup(b.shader, name);
b.shader->info.cs.local_size[0] = 16;
b.shader->info.cs.local_size[1] = 16;
b.shader->info.cs.local_size[2] = 1;
nir_variable *input_img = nir_variable_create(b.shader, nir_var_uniform,
sampler_type, "s_tex");
input_img->data.descriptor_set = 0;
input_img->data.binding = 0;
nir_variable *output_img = nir_variable_create(b.shader, nir_var_uniform,
img_type, "out_img");
output_img->data.descriptor_set = 0;
output_img->data.binding = 1;
nir_ssa_def *invoc_id = nir_load_system_value(&b, nir_intrinsic_load_local_invocation_id, 0);
nir_ssa_def *wg_id = nir_load_system_value(&b, nir_intrinsic_load_work_group_id, 0);
nir_ssa_def *block_size = nir_imm_ivec4(&b,
b.shader->info.cs.local_size[0],
b.shader->info.cs.local_size[1],
b.shader->info.cs.local_size[2], 0);
nir_ssa_def *global_id = nir_iadd(&b, nir_imul(&b, wg_id, block_size), invoc_id);
nir_intrinsic_instr *src_offset = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
src_offset->src[0] = nir_src_for_ssa(nir_imm_int(&b, 0));
src_offset->num_components = 2;
nir_ssa_dest_init(&src_offset->instr, &src_offset->dest, 2, 32, "src_offset");
nir_builder_instr_insert(&b, &src_offset->instr);
nir_intrinsic_instr *dst_offset = nir_intrinsic_instr_create(b.shader, nir_intrinsic_load_push_constant);
dst_offset->src[0] = nir_src_for_ssa(nir_imm_int(&b, 8));
dst_offset->num_components = 2;
nir_ssa_dest_init(&dst_offset->instr, &dst_offset->dest, 2, 32, "dst_offset");
nir_builder_instr_insert(&b, &dst_offset->instr);
nir_ssa_def *img_coord = nir_iadd(&b, global_id, &src_offset->dest.ssa);
/* do a txf_ms on each sample */
nir_ssa_def *tmp;
nir_tex_instr *tex = nir_tex_instr_create(b.shader, 2);
tex->sampler_dim = GLSL_SAMPLER_DIM_MS;
tex->op = nir_texop_txf_ms;
tex->src[0].src_type = nir_tex_src_coord;
tex->src[0].src = nir_src_for_ssa(img_coord);
tex->src[1].src_type = nir_tex_src_ms_index;
tex->src[1].src = nir_src_for_ssa(nir_imm_int(&b, 0));
tex->dest_type = nir_type_float;
tex->is_array = false;
tex->coord_components = 2;
tex->texture = nir_deref_var_create(tex, input_img);
tex->sampler = NULL;
nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, "tex");
nir_builder_instr_insert(&b, &tex->instr);
tmp = &tex->dest.ssa;
nir_variable *color =
nir_local_variable_create(b.impl, glsl_vec4_type(), "color");
if (!is_integer && samples > 1) {
nir_tex_instr *tex_all_same = nir_tex_instr_create(b.shader, 1);
tex_all_same->sampler_dim = GLSL_SAMPLER_DIM_MS;
tex_all_same->op = nir_texop_samples_identical;
tex_all_same->src[0].src_type = nir_tex_src_coord;
tex_all_same->src[0].src = nir_src_for_ssa(img_coord);
tex_all_same->dest_type = nir_type_float;
tex_all_same->is_array = false;
tex_all_same->coord_components = 2;
tex_all_same->texture = nir_deref_var_create(tex_all_same, input_img);
tex_all_same->sampler = NULL;
nir_ssa_dest_init(&tex_all_same->instr, &tex_all_same->dest, 1, 32, "tex");
nir_builder_instr_insert(&b, &tex_all_same->instr);
nir_ssa_def *all_same = nir_ine(&b, &tex_all_same->dest.ssa, nir_imm_int(&b, 0));
nir_if *if_stmt = nir_if_create(b.shader);
if_stmt->condition = nir_src_for_ssa(all_same);
nir_cf_node_insert(b.cursor, &if_stmt->cf_node);
b.cursor = nir_after_cf_list(&if_stmt->then_list);
for (int i = 1; i < samples; i++) {
nir_tex_instr *tex_add = nir_tex_instr_create(b.shader, 2);
tex_add->sampler_dim = GLSL_SAMPLER_DIM_MS;
tex_add->op = nir_texop_txf_ms;
tex_add->src[0].src_type = nir_tex_src_coord;
tex_add->src[0].src = nir_src_for_ssa(img_coord);
tex_add->src[1].src_type = nir_tex_src_ms_index;
tex_add->src[1].src = nir_src_for_ssa(nir_imm_int(&b, i));
tex_add->dest_type = nir_type_float;
tex_add->is_array = false;
tex_add->coord_components = 2;
tex_add->texture = nir_deref_var_create(tex_add, input_img);
tex_add->sampler = NULL;
nir_ssa_dest_init(&tex_add->instr, &tex_add->dest, 4, 32, "tex");
nir_builder_instr_insert(&b, &tex_add->instr);
tmp = nir_fadd(&b, tmp, &tex_add->dest.ssa);
}
tmp = nir_fdiv(&b, tmp, nir_imm_float(&b, samples));
nir_store_var(&b, color, tmp, 0xf);
b.cursor = nir_after_cf_list(&if_stmt->else_list);
outer_if = if_stmt;
}
nir_store_var(&b, color, &tex->dest.ssa, 0xf);
if (outer_if)
b.cursor = nir_after_cf_node(&outer_if->cf_node);
nir_ssa_def *newv = nir_load_var(&b, color);
nir_ssa_def *coord = nir_iadd(&b, global_id, &dst_offset->dest.ssa);
nir_intrinsic_instr *store = nir_intrinsic_instr_create(b.shader, nir_intrinsic_image_store);
store->src[0] = nir_src_for_ssa(coord);
store->src[1] = nir_src_for_ssa(nir_ssa_undef(&b, 1, 32));
store->src[2] = nir_src_for_ssa(newv);
store->variables[0] = nir_deref_var_create(store, output_img);
nir_builder_instr_insert(&b, &store->instr);
return b.shader;
}
static VkResult
create_layout(struct radv_device *device)
{
VkResult result;
/*
* two descriptors one for the image being sampled
* one for the buffer being written.
*/
VkDescriptorSetLayoutCreateInfo ds_create_info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 2,
.pBindings = (VkDescriptorSetLayoutBinding[]) {
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = NULL
},
}
};
result = radv_CreateDescriptorSetLayout(radv_device_to_handle(device),
&ds_create_info,
&device->meta_state.alloc,
&device->meta_state.resolve_compute.ds_layout);
if (result != VK_SUCCESS)
goto fail;
VkPipelineLayoutCreateInfo pl_create_info = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 1,
.pSetLayouts = &device->meta_state.resolve_compute.ds_layout,
.pushConstantRangeCount = 1,
.pPushConstantRanges = &(VkPushConstantRange){VK_SHADER_STAGE_COMPUTE_BIT, 0, 16},
};
result = radv_CreatePipelineLayout(radv_device_to_handle(device),
&pl_create_info,
&device->meta_state.alloc,
&device->meta_state.resolve_compute.p_layout);
if (result != VK_SUCCESS)
goto fail;
return VK_SUCCESS;
fail:
return result;
}
static VkResult
create_resolve_pipeline(struct radv_device *device,
int samples,
bool is_integer,
VkPipeline *pipeline)
{
VkResult result;
struct radv_shader_module cs = { .nir = NULL };
cs.nir = build_resolve_compute_shader(device, is_integer, samples);
/* compute shader */
VkPipelineShaderStageCreateInfo pipeline_shader_stage = {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = radv_shader_module_to_handle(&cs),
.pName = "main",
.pSpecializationInfo = NULL,
};
VkComputePipelineCreateInfo vk_pipeline_info = {
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
.stage = pipeline_shader_stage,
.flags = 0,
.layout = device->meta_state.resolve_compute.p_layout,
};
result = radv_CreateComputePipelines(radv_device_to_handle(device),
radv_pipeline_cache_to_handle(&device->meta_state.cache),
1, &vk_pipeline_info, NULL,
pipeline);
if (result != VK_SUCCESS)
goto fail;
ralloc_free(cs.nir);
return VK_SUCCESS;
fail:
ralloc_free(cs.nir);
return result;
}
VkResult
radv_device_init_meta_resolve_compute_state(struct radv_device *device)
{
struct radv_meta_state *state = &device->meta_state;
VkResult res;
memset(&device->meta_state.resolve_compute, 0, sizeof(device->meta_state.resolve_compute));
res = create_layout(device);
if (res != VK_SUCCESS)
return res;
for (uint32_t i = 0; i < MAX_SAMPLES_LOG2; ++i) {
uint32_t samples = 1 << i;
res = create_resolve_pipeline(device, samples, false,
&state->resolve_compute.rc[i].pipeline);
res = create_resolve_pipeline(device, samples, true,
&state->resolve_compute.rc[i].i_pipeline);
}
return res;
}
void
radv_device_finish_meta_resolve_compute_state(struct radv_device *device)
{
struct radv_meta_state *state = &device->meta_state;
for (uint32_t i = 0; i < MAX_SAMPLES_LOG2; ++i) {
radv_DestroyPipeline(radv_device_to_handle(device),
state->resolve_compute.rc[i].pipeline,
&state->alloc);
radv_DestroyPipeline(radv_device_to_handle(device),
state->resolve_compute.rc[i].i_pipeline,
&state->alloc);
}
radv_DestroyDescriptorSetLayout(radv_device_to_handle(device),
state->resolve_compute.ds_layout,
&state->alloc);
radv_DestroyPipelineLayout(radv_device_to_handle(device),
state->resolve_compute.p_layout,
&state->alloc);
}
void radv_meta_resolve_compute_image(struct radv_cmd_buffer *cmd_buffer,
struct radv_image *src_image,
VkImageLayout src_image_layout,
struct radv_image *dest_image,
VkImageLayout dest_image_layout,
uint32_t region_count,
const VkImageResolve *regions)
{
struct radv_device *device = cmd_buffer->device;
struct radv_meta_saved_compute_state saved_state;
const uint32_t samples = src_image->samples;
const uint32_t samples_log2 = ffs(samples) - 1;
radv_meta_save_compute(&saved_state, cmd_buffer, 16);
for (uint32_t r = 0; r < region_count; ++r) {
const VkImageResolve *region = &regions[r];
assert(region->srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
assert(region->dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
assert(region->srcSubresource.layerCount == region->dstSubresource.layerCount);
const uint32_t src_base_layer =
radv_meta_get_iview_layer(src_image, &region->srcSubresource,
&region->srcOffset);
const uint32_t dest_base_layer =
radv_meta_get_iview_layer(dest_image, &region->dstSubresource,
&region->dstOffset);
const struct VkExtent3D extent =
radv_sanitize_image_extent(src_image->type, region->extent);
const struct VkOffset3D srcOffset =
radv_sanitize_image_offset(src_image->type, region->srcOffset);
const struct VkOffset3D dstOffset =
radv_sanitize_image_offset(dest_image->type, region->dstOffset);
for (uint32_t layer = 0; layer < region->srcSubresource.layerCount;
++layer) {
struct radv_image_view src_iview;
VkDescriptorSet set;
radv_image_view_init(&src_iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = radv_image_to_handle(src_image),
.viewType = radv_meta_get_view_type(src_image),
.format = src_image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = region->srcSubresource.mipLevel,
.levelCount = 1,
.baseArrayLayer = src_base_layer + layer,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_SAMPLED_BIT);
struct radv_image_view dest_iview;
radv_image_view_init(&dest_iview, cmd_buffer->device,
&(VkImageViewCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = radv_image_to_handle(dest_image),
.viewType = radv_meta_get_view_type(dest_image),
.format = dest_image->vk_format,
.subresourceRange = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = region->dstSubresource.mipLevel,
.levelCount = 1,
.baseArrayLayer = dest_base_layer + layer,
.layerCount = 1,
},
},
cmd_buffer, VK_IMAGE_USAGE_STORAGE_BIT);
radv_temp_descriptor_set_create(device, cmd_buffer,
device->meta_state.resolve_compute.ds_layout,
&set);
radv_UpdateDescriptorSets(radv_device_to_handle(device),
2, /* writeCount */
(VkWriteDescriptorSet[]) {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = set,
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.pImageInfo = (VkDescriptorImageInfo[]) {
{
.sampler = NULL,
.imageView = radv_image_view_to_handle(&src_iview),
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
},
}
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = set,
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,
.pImageInfo = (VkDescriptorImageInfo[]) {
{
.sampler = NULL,
.imageView = radv_image_view_to_handle(&dest_iview),
.imageLayout = VK_IMAGE_LAYOUT_GENERAL,
},
}
}
}, 0, NULL);
radv_CmdBindDescriptorSets(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE,
device->meta_state.resolve_compute.p_layout, 0, 1,
&set, 0, NULL);
VkPipeline pipeline;
if (vk_format_is_int(src_image->vk_format))
pipeline = device->meta_state.resolve_compute.rc[samples_log2].i_pipeline;
else
pipeline = device->meta_state.resolve_compute.rc[samples_log2].pipeline;
if (cmd_buffer->state.compute_pipeline != radv_pipeline_from_handle(pipeline)) {
radv_CmdBindPipeline(radv_cmd_buffer_to_handle(cmd_buffer),
VK_PIPELINE_BIND_POINT_COMPUTE, pipeline);
}
unsigned push_constants[4] = {
srcOffset.x,
srcOffset.y,
dstOffset.x,
dstOffset.y,
};
radv_CmdPushConstants(radv_cmd_buffer_to_handle(cmd_buffer),
device->meta_state.resolve_compute.p_layout,
VK_SHADER_STAGE_COMPUTE_BIT, 0, 16,
push_constants);
radv_unaligned_dispatch(cmd_buffer, extent.width, extent.height, 1);
radv_temp_descriptor_set_destroy(cmd_buffer->device, set);
}
}
radv_meta_restore_compute(&saved_state, cmd_buffer, 16);
}

183
src/amd/vulkan/radv_pass.c Normal file
View File

@ -0,0 +1,183 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based in part on anv driver which is:
* Copyright © 2015 Intel 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 "radv_private.h"
VkResult radv_CreateRenderPass(
VkDevice _device,
const VkRenderPassCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkRenderPass* pRenderPass)
{
RADV_FROM_HANDLE(radv_device, device, _device);
struct radv_render_pass *pass;
size_t size;
size_t attachments_offset;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO);
size = sizeof(*pass);
size += pCreateInfo->subpassCount * sizeof(pass->subpasses[0]);
attachments_offset = size;
size += pCreateInfo->attachmentCount * sizeof(pass->attachments[0]);
pass = radv_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (pass == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
memset(pass, 0, size);
pass->attachment_count = pCreateInfo->attachmentCount;
pass->subpass_count = pCreateInfo->subpassCount;
pass->attachments = (void *) pass + attachments_offset;
for (uint32_t i = 0; i < pCreateInfo->attachmentCount; i++) {
struct radv_render_pass_attachment *att = &pass->attachments[i];
att->format = pCreateInfo->pAttachments[i].format;
att->samples = pCreateInfo->pAttachments[i].samples;
att->load_op = pCreateInfo->pAttachments[i].loadOp;
att->stencil_load_op = pCreateInfo->pAttachments[i].stencilLoadOp;
att->initial_layout = pCreateInfo->pAttachments[i].initialLayout;
att->final_layout = pCreateInfo->pAttachments[i].finalLayout;
// att->store_op = pCreateInfo->pAttachments[i].storeOp;
// att->stencil_store_op = pCreateInfo->pAttachments[i].stencilStoreOp;
}
uint32_t subpass_attachment_count = 0;
VkAttachmentReference *p;
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i];
subpass_attachment_count +=
desc->inputAttachmentCount +
desc->colorAttachmentCount +
/* Count colorAttachmentCount again for resolve_attachments */
desc->colorAttachmentCount;
}
if (subpass_attachment_count) {
pass->subpass_attachments =
radv_alloc2(&device->alloc, pAllocator,
subpass_attachment_count * sizeof(VkAttachmentReference), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (pass->subpass_attachments == NULL) {
radv_free2(&device->alloc, pAllocator, pass);
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
}
} else
pass->subpass_attachments = NULL;
p = pass->subpass_attachments;
for (uint32_t i = 0; i < pCreateInfo->subpassCount; i++) {
const VkSubpassDescription *desc = &pCreateInfo->pSubpasses[i];
struct radv_subpass *subpass = &pass->subpasses[i];
subpass->input_count = desc->inputAttachmentCount;
subpass->color_count = desc->colorAttachmentCount;
if (desc->inputAttachmentCount > 0) {
subpass->input_attachments = p;
p += desc->inputAttachmentCount;
for (uint32_t j = 0; j < desc->inputAttachmentCount; j++) {
subpass->input_attachments[j]
= desc->pInputAttachments[j];
}
}
if (desc->colorAttachmentCount > 0) {
subpass->color_attachments = p;
p += desc->colorAttachmentCount;
for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) {
subpass->color_attachments[j]
= desc->pColorAttachments[j];
}
}
subpass->has_resolve = false;
if (desc->pResolveAttachments) {
subpass->resolve_attachments = p;
p += desc->colorAttachmentCount;
for (uint32_t j = 0; j < desc->colorAttachmentCount; j++) {
uint32_t a = desc->pResolveAttachments[j].attachment;
subpass->resolve_attachments[j]
= desc->pResolveAttachments[j];
if (a != VK_ATTACHMENT_UNUSED)
subpass->has_resolve = true;
}
}
if (desc->pDepthStencilAttachment) {
subpass->depth_stencil_attachment =
*desc->pDepthStencilAttachment;
} else {
subpass->depth_stencil_attachment.attachment = VK_ATTACHMENT_UNUSED;
}
}
for (unsigned i = 0; i < pCreateInfo->dependencyCount; ++i) {
uint32_t dst = pCreateInfo->pDependencies[i].dstSubpass;
if (dst == VK_SUBPASS_EXTERNAL) {
pass->end_barrier.src_stage_mask = pCreateInfo->pDependencies[i].srcStageMask;
pass->end_barrier.src_access_mask = pCreateInfo->pDependencies[i].srcAccessMask;
pass->end_barrier.dst_access_mask = pCreateInfo->pDependencies[i].dstAccessMask;
} else {
pass->subpasses[dst].start_barrier.src_stage_mask = pCreateInfo->pDependencies[i].srcStageMask;
pass->subpasses[dst].start_barrier.src_access_mask = pCreateInfo->pDependencies[i].srcAccessMask;
pass->subpasses[dst].start_barrier.dst_access_mask = pCreateInfo->pDependencies[i].dstAccessMask;
}
}
*pRenderPass = radv_render_pass_to_handle(pass);
return VK_SUCCESS;
}
void radv_DestroyRenderPass(
VkDevice _device,
VkRenderPass _pass,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_render_pass, pass, _pass);
if (!_pass)
return;
radv_free2(&device->alloc, pAllocator, pass->subpass_attachments);
radv_free2(&device->alloc, pAllocator, pass);
}
void radv_GetRenderAreaGranularity(
VkDevice device,
VkRenderPass renderPass,
VkExtent2D* pGranularity)
{
pGranularity->width = 1;
pGranularity->height = 1;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,475 @@
/*
* Copyright © 2015 Intel 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 "util/mesa-sha1.h"
#include "util/debug.h"
#include "radv_private.h"
#include "ac_nir_to_llvm.h"
struct cache_entry {
unsigned char sha1[20];
uint32_t code_size;
struct ac_shader_variant_info variant_info;
struct ac_shader_config config;
uint32_t rsrc1, rsrc2;
struct radv_shader_variant *variant;
uint32_t code[0];
};
void
radv_pipeline_cache_init(struct radv_pipeline_cache *cache,
struct radv_device *device)
{
cache->device = device;
pthread_mutex_init(&cache->mutex, NULL);
cache->modified = false;
cache->kernel_count = 0;
cache->total_size = 0;
cache->table_size = 1024;
const size_t byte_size = cache->table_size * sizeof(cache->hash_table[0]);
cache->hash_table = malloc(byte_size);
/* We don't consider allocation failure fatal, we just start with a 0-sized
* cache. */
if (cache->hash_table == NULL ||
!env_var_as_boolean("RADV_ENABLE_PIPELINE_CACHE", true))
cache->table_size = 0;
else
memset(cache->hash_table, 0, byte_size);
}
void
radv_pipeline_cache_finish(struct radv_pipeline_cache *cache)
{
for (unsigned i = 0; i < cache->table_size; ++i)
if (cache->hash_table[i]) {
if (cache->hash_table[i]->variant)
radv_shader_variant_destroy(cache->device,
cache->hash_table[i]->variant);
radv_free(&cache->alloc, cache->hash_table[i]);
}
pthread_mutex_destroy(&cache->mutex);
free(cache->hash_table);
}
static uint32_t
entry_size(struct cache_entry *entry)
{
return sizeof(*entry) + entry->code_size;
}
void
radv_hash_shader(unsigned char *hash, struct radv_shader_module *module,
const char *entrypoint,
const VkSpecializationInfo *spec_info,
const struct radv_pipeline_layout *layout,
const union ac_shader_variant_key *key)
{
struct mesa_sha1 *ctx;
ctx = _mesa_sha1_init();
if (key)
_mesa_sha1_update(ctx, key, sizeof(*key));
_mesa_sha1_update(ctx, module->sha1, sizeof(module->sha1));
_mesa_sha1_update(ctx, entrypoint, strlen(entrypoint));
if (layout)
_mesa_sha1_update(ctx, layout->sha1, sizeof(layout->sha1));
if (spec_info) {
_mesa_sha1_update(ctx, spec_info->pMapEntries,
spec_info->mapEntryCount * sizeof spec_info->pMapEntries[0]);
_mesa_sha1_update(ctx, spec_info->pData, spec_info->dataSize);
}
_mesa_sha1_final(ctx, hash);
}
static struct cache_entry *
radv_pipeline_cache_search_unlocked(struct radv_pipeline_cache *cache,
const unsigned char *sha1)
{
const uint32_t mask = cache->table_size - 1;
const uint32_t start = (*(uint32_t *) sha1);
for (uint32_t i = 0; i < cache->table_size; i++) {
const uint32_t index = (start + i) & mask;
struct cache_entry *entry = cache->hash_table[index];
if (!entry)
return NULL;
if (memcmp(entry->sha1, sha1, sizeof(entry->sha1)) == 0) {
return entry;
}
}
unreachable("hash table should never be full");
}
static struct cache_entry *
radv_pipeline_cache_search(struct radv_pipeline_cache *cache,
const unsigned char *sha1)
{
struct cache_entry *entry;
pthread_mutex_lock(&cache->mutex);
entry = radv_pipeline_cache_search_unlocked(cache, sha1);
pthread_mutex_unlock(&cache->mutex);
return entry;
}
struct radv_shader_variant *
radv_create_shader_variant_from_pipeline_cache(struct radv_device *device,
struct radv_pipeline_cache *cache,
const unsigned char *sha1)
{
struct cache_entry *entry = radv_pipeline_cache_search(cache, sha1);
if (!entry)
return NULL;
if (!entry->variant) {
struct radv_shader_variant *variant;
variant = calloc(1, sizeof(struct radv_shader_variant));
if (!variant)
return NULL;
variant->config = entry->config;
variant->info = entry->variant_info;
variant->rsrc1 = entry->rsrc1;
variant->rsrc2 = entry->rsrc2;
variant->ref_count = 1;
variant->bo = device->ws->buffer_create(device->ws, entry->code_size, 256,
RADEON_DOMAIN_GTT, RADEON_FLAG_CPU_ACCESS);
void *ptr = device->ws->buffer_map(variant->bo);
memcpy(ptr, entry->code, entry->code_size);
device->ws->buffer_unmap(variant->bo);
entry->variant = variant;
}
__sync_fetch_and_add(&entry->variant->ref_count, 1);
return entry->variant;
}
static void
radv_pipeline_cache_set_entry(struct radv_pipeline_cache *cache,
struct cache_entry *entry)
{
const uint32_t mask = cache->table_size - 1;
const uint32_t start = (*(uint32_t *) entry->sha1);
/* We'll always be able to insert when we get here. */
assert(cache->kernel_count < cache->table_size / 2);
for (uint32_t i = 0; i < cache->table_size; i++) {
const uint32_t index = (start + i) & mask;
if (!cache->hash_table[index]) {
cache->hash_table[index] = entry;
break;
}
}
cache->total_size += entry_size(entry);
cache->kernel_count++;
}
static VkResult
radv_pipeline_cache_grow(struct radv_pipeline_cache *cache)
{
const uint32_t table_size = cache->table_size * 2;
const uint32_t old_table_size = cache->table_size;
const size_t byte_size = table_size * sizeof(cache->hash_table[0]);
struct cache_entry **table;
struct cache_entry **old_table = cache->hash_table;
table = malloc(byte_size);
if (table == NULL)
return VK_ERROR_OUT_OF_HOST_MEMORY;
cache->hash_table = table;
cache->table_size = table_size;
cache->kernel_count = 0;
cache->total_size = 0;
memset(cache->hash_table, 0, byte_size);
for (uint32_t i = 0; i < old_table_size; i++) {
struct cache_entry *entry = old_table[i];
if (!entry)
continue;
radv_pipeline_cache_set_entry(cache, entry);
}
free(old_table);
return VK_SUCCESS;
}
static void
radv_pipeline_cache_add_entry(struct radv_pipeline_cache *cache,
struct cache_entry *entry)
{
if (cache->kernel_count == cache->table_size / 2)
radv_pipeline_cache_grow(cache);
/* Failing to grow that hash table isn't fatal, but may mean we don't
* have enough space to add this new kernel. Only add it if there's room.
*/
if (cache->kernel_count < cache->table_size / 2)
radv_pipeline_cache_set_entry(cache, entry);
}
struct radv_shader_variant *
radv_pipeline_cache_insert_shader(struct radv_pipeline_cache *cache,
const unsigned char *sha1,
struct radv_shader_variant *variant,
const void *code, unsigned code_size)
{
pthread_mutex_lock(&cache->mutex);
struct cache_entry *entry = radv_pipeline_cache_search_unlocked(cache, sha1);
if (entry) {
if (entry->variant) {
radv_shader_variant_destroy(cache->device, variant);
variant = entry->variant;
} else {
entry->variant = variant;
}
__sync_fetch_and_add(&variant->ref_count, 1);
pthread_mutex_unlock(&cache->mutex);
return variant;
}
entry = radv_alloc(&cache->alloc, sizeof(*entry) + code_size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_CACHE);
if (!entry) {
pthread_mutex_unlock(&cache->mutex);
return variant;
}
memcpy(entry->sha1, sha1, 20);
memcpy(entry->code, code, code_size);
entry->config = variant->config;
entry->variant_info = variant->info;
entry->rsrc1 = variant->rsrc1;
entry->rsrc2 = variant->rsrc2;
entry->code_size = code_size;
entry->variant = variant;
__sync_fetch_and_add(&variant->ref_count, 1);
radv_pipeline_cache_add_entry(cache, entry);
cache->modified = true;
pthread_mutex_unlock(&cache->mutex);
return variant;
}
struct cache_header {
uint32_t header_size;
uint32_t header_version;
uint32_t vendor_id;
uint32_t device_id;
uint8_t uuid[VK_UUID_SIZE];
};
void
radv_pipeline_cache_load(struct radv_pipeline_cache *cache,
const void *data, size_t size)
{
struct radv_device *device = cache->device;
struct cache_header header;
uint8_t uuid[VK_UUID_SIZE];
if (size < sizeof(header))
return;
memcpy(&header, data, sizeof(header));
if (header.header_size < sizeof(header))
return;
if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
return;
if (header.vendor_id != 0x1002)
return;
if (header.device_id != device->instance->physicalDevice.rad_info.pci_id)
return;
radv_device_get_cache_uuid(uuid);
if (memcmp(header.uuid, uuid, VK_UUID_SIZE) != 0)
return;
char *end = (void *) data + size;
char *p = (void *) data + header.header_size;
while (end - p >= sizeof(struct cache_entry)) {
struct cache_entry *entry = (struct cache_entry*)p;
struct cache_entry *dest_entry;
if(end - p < sizeof(*entry) + entry->code_size)
break;
dest_entry = radv_alloc(&cache->alloc, sizeof(*entry) + entry->code_size,
8, VK_SYSTEM_ALLOCATION_SCOPE_CACHE);
if (dest_entry) {
memcpy(dest_entry, entry, sizeof(*entry) + entry->code_size);
dest_entry->variant = NULL;
radv_pipeline_cache_add_entry(cache, dest_entry);
}
p += sizeof (*entry) + entry->code_size;
}
}
VkResult radv_CreatePipelineCache(
VkDevice _device,
const VkPipelineCacheCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkPipelineCache* pPipelineCache)
{
RADV_FROM_HANDLE(radv_device, device, _device);
struct radv_pipeline_cache *cache;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO);
assert(pCreateInfo->flags == 0);
cache = radv_alloc2(&device->alloc, pAllocator,
sizeof(*cache), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (cache == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
if (pAllocator)
cache->alloc = *pAllocator;
else
cache->alloc = device->alloc;
radv_pipeline_cache_init(cache, device);
if (pCreateInfo->initialDataSize > 0) {
radv_pipeline_cache_load(cache,
pCreateInfo->pInitialData,
pCreateInfo->initialDataSize);
}
*pPipelineCache = radv_pipeline_cache_to_handle(cache);
return VK_SUCCESS;
}
void radv_DestroyPipelineCache(
VkDevice _device,
VkPipelineCache _cache,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_pipeline_cache, cache, _cache);
if (!cache)
return;
radv_pipeline_cache_finish(cache);
radv_free2(&device->alloc, pAllocator, cache);
}
VkResult radv_GetPipelineCacheData(
VkDevice _device,
VkPipelineCache _cache,
size_t* pDataSize,
void* pData)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_pipeline_cache, cache, _cache);
struct cache_header *header;
VkResult result = VK_SUCCESS;
const size_t size = sizeof(*header) + cache->total_size;
if (pData == NULL) {
*pDataSize = size;
return VK_SUCCESS;
}
if (*pDataSize < sizeof(*header)) {
*pDataSize = 0;
return VK_INCOMPLETE;
}
void *p = pData, *end = pData + *pDataSize;
header = p;
header->header_size = sizeof(*header);
header->header_version = VK_PIPELINE_CACHE_HEADER_VERSION_ONE;
header->vendor_id = 0x1002;
header->device_id = device->instance->physicalDevice.rad_info.pci_id;
radv_device_get_cache_uuid(header->uuid);
p += header->header_size;
struct cache_entry *entry;
for (uint32_t i = 0; i < cache->table_size; i++) {
if (!cache->hash_table[i])
continue;
entry = cache->hash_table[i];
const uint32_t size = entry_size(entry);
if (end < p + size) {
result = VK_INCOMPLETE;
break;
}
memcpy(p, entry, size);
((struct cache_entry*)p)->variant = NULL;
p += size;
}
*pDataSize = p - pData;
return result;
}
static void
radv_pipeline_cache_merge(struct radv_pipeline_cache *dst,
struct radv_pipeline_cache *src)
{
for (uint32_t i = 0; i < src->table_size; i++) {
struct cache_entry *entry = src->hash_table[i];
if (!entry || radv_pipeline_cache_search(dst, entry->sha1))
continue;
radv_pipeline_cache_add_entry(dst, entry);
src->hash_table[i] = NULL;
}
}
VkResult radv_MergePipelineCaches(
VkDevice _device,
VkPipelineCache destCache,
uint32_t srcCacheCount,
const VkPipelineCache* pSrcCaches)
{
RADV_FROM_HANDLE(radv_pipeline_cache, dst, destCache);
for (uint32_t i = 0; i < srcCacheCount; i++) {
RADV_FROM_HANDLE(radv_pipeline_cache, src, pSrcCaches[i]);
radv_pipeline_cache_merge(dst, src);
}
return VK_SUCCESS;
}

File diff suppressed because it is too large Load Diff

415
src/amd/vulkan/radv_query.c Normal file
View File

@ -0,0 +1,415 @@
/*
* Copyrigh 2016 Red Hat Inc.
* Based on anv:
* Copyright © 2015 Intel 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 <assert.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "radv_private.h"
#include "radv_cs.h"
#include "sid.h"
static unsigned get_max_db(struct radv_device *device)
{
unsigned num_db = device->instance->physicalDevice.rad_info.num_render_backends;
unsigned rb_mask = device->instance->physicalDevice.rad_info.enabled_rb_mask;
if (device->instance->physicalDevice.rad_info.chip_class == SI)
num_db = 8;
else
num_db = MAX2(8, num_db);
/* Otherwise we need to change the query reset procedure */
assert(rb_mask == ((1ull << num_db) - 1));
return num_db;
}
VkResult radv_CreateQueryPool(
VkDevice _device,
const VkQueryPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkQueryPool* pQueryPool)
{
RADV_FROM_HANDLE(radv_device, device, _device);
uint64_t size;
struct radv_query_pool *pool = radv_alloc2(&device->alloc, pAllocator,
sizeof(*pool), 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (!pool)
return VK_ERROR_OUT_OF_HOST_MEMORY;
switch(pCreateInfo->queryType) {
case VK_QUERY_TYPE_OCCLUSION:
/* 16 bytes tmp. buffer as the compute packet writes 64 bits, but
* the app. may have 32 bits of space. */
pool->stride = 16 * get_max_db(device) + 16;
break;
case VK_QUERY_TYPE_PIPELINE_STATISTICS:
pool->stride = 16 * 11;
break;
case VK_QUERY_TYPE_TIMESTAMP:
pool->stride = 8;
break;
default:
unreachable("creating unhandled query type");
}
pool->type = pCreateInfo->queryType;
pool->availability_offset = pool->stride * pCreateInfo->queryCount;
size = pool->availability_offset + 4 * pCreateInfo->queryCount;
pool->bo = device->ws->buffer_create(device->ws, size,
64, RADEON_DOMAIN_GTT, 0);
if (!pool->bo) {
radv_free2(&device->alloc, pAllocator, pool);
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
pool->ptr = device->ws->buffer_map(pool->bo);
if (!pool->ptr) {
device->ws->buffer_destroy(pool->bo);
radv_free2(&device->alloc, pAllocator, pool);
return VK_ERROR_OUT_OF_DEVICE_MEMORY;
}
memset(pool->ptr, 0, size);
*pQueryPool = radv_query_pool_to_handle(pool);
return VK_SUCCESS;
}
void radv_DestroyQueryPool(
VkDevice _device,
VkQueryPool _pool,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(radv_query_pool, pool, _pool);
if (!pool)
return;
device->ws->buffer_destroy(pool->bo);
radv_free2(&device->alloc, pAllocator, pool);
}
VkResult radv_GetQueryPoolResults(
VkDevice _device,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
size_t dataSize,
void* pData,
VkDeviceSize stride,
VkQueryResultFlags flags)
{
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
char *data = pData;
VkResult result = VK_SUCCESS;
for(unsigned i = 0; i < queryCount; ++i, data += stride) {
char *dest = data;
unsigned query = firstQuery + i;
char *src = pool->ptr + query * pool->stride;
uint32_t available;
if (flags & VK_QUERY_RESULT_WAIT_BIT) {
while(!*(volatile uint32_t*)(pool->ptr + pool->availability_offset + 4 * query))
;
}
if (!*(uint32_t*)(pool->ptr + pool->availability_offset + 4 * query) &&
!(flags & VK_QUERY_RESULT_PARTIAL_BIT)) {
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT)
*(uint32_t*)dest = 0;
result = VK_NOT_READY;
continue;
}
available = *(uint32_t*)(pool->ptr + pool->availability_offset + 4 * query);
switch (pool->type) {
case VK_QUERY_TYPE_TIMESTAMP:
if (flags & VK_QUERY_RESULT_64_BIT) {
*(uint64_t*)dest = *(uint64_t*)src;
dest += 8;
} else {
*(uint32_t*)dest = *(uint32_t*)src;
dest += 4;
}
break;
case VK_QUERY_TYPE_OCCLUSION: {
uint64_t result = *(uint64_t*)(src + pool->stride - 16);
if (flags & VK_QUERY_RESULT_64_BIT) {
*(uint64_t*)dest = result;
dest += 8;
} else {
*(uint32_t*)dest = result;
dest += 4;
}
break;
default:
unreachable("trying to get results of unhandled query type");
}
}
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
*(uint32_t*)dest = available;
dest += 4;
}
}
return result;
}
void radv_CmdCopyQueryPoolResults(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount,
VkBuffer dstBuffer,
VkDeviceSize dstOffset,
VkDeviceSize stride,
VkQueryResultFlags flags)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
RADV_FROM_HANDLE(radv_buffer, dst_buffer, dstBuffer);
struct radeon_winsys_cs *cs = cmd_buffer->cs;
uint64_t va = cmd_buffer->device->ws->buffer_get_va(pool->bo);
uint64_t dest_va = cmd_buffer->device->ws->buffer_get_va(dst_buffer->bo);
dest_va += dst_buffer->offset + dstOffset;
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, pool->bo, 8);
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, dst_buffer->bo, 8);
for(unsigned i = 0; i < queryCount; ++i, dest_va += stride) {
unsigned query = firstQuery + i;
uint64_t local_src_va = va + query * pool->stride;
unsigned elem_size = (flags & VK_QUERY_RESULT_64_BIT) ? 8 : 4;
unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws, cs, 26);
if (flags & VK_QUERY_RESULT_WAIT_BIT) {
/* TODO, not sure if there is any case where we won't always be ready yet */
uint64_t avail_va = va + pool->availability_offset + 4 * query;
/* This waits on the ME. All copies below are done on the ME */
radeon_emit(cs, PKT3(PKT3_WAIT_REG_MEM, 5, 0));
radeon_emit(cs, WAIT_REG_MEM_EQUAL | WAIT_REG_MEM_MEM_SPACE(1));
radeon_emit(cs, avail_va);
radeon_emit(cs, avail_va >> 32);
radeon_emit(cs, 1); /* reference value */
radeon_emit(cs, 0xffffffff); /* mask */
radeon_emit(cs, 4); /* poll interval */
}
switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION:
local_src_va += pool->stride - 16;
case VK_QUERY_TYPE_TIMESTAMP:
radeon_emit(cs, PKT3(PKT3_COPY_DATA, 4, 0));
radeon_emit(cs, COPY_DATA_SRC_SEL(COPY_DATA_MEM) |
COPY_DATA_DST_SEL(COPY_DATA_MEM) |
((flags & VK_QUERY_RESULT_64_BIT) ? COPY_DATA_COUNT_SEL : 0));
radeon_emit(cs, local_src_va);
radeon_emit(cs, local_src_va >> 32);
radeon_emit(cs, dest_va);
radeon_emit(cs, dest_va >> 32);
break;
default:
unreachable("trying to get results of unhandled query type");
}
/* The flag could be still changed while the data copy is busy and we
* then might have invalid data, but a ready flag. However, the availability
* writes happen on the ME too, so they should be synchronized. Might need to
* revisit this with multiple queues.
*/
if (flags & VK_QUERY_RESULT_WITH_AVAILABILITY_BIT) {
uint64_t avail_va = va + pool->availability_offset + 4 * query;
uint64_t avail_dest_va = dest_va;
if (pool->type != VK_QUERY_TYPE_PIPELINE_STATISTICS)
avail_dest_va += elem_size;
else
abort();
radeon_emit(cs, PKT3(PKT3_COPY_DATA, 4, 0));
radeon_emit(cs, COPY_DATA_SRC_SEL(COPY_DATA_MEM) |
COPY_DATA_DST_SEL(COPY_DATA_MEM));
radeon_emit(cs, avail_va);
radeon_emit(cs, avail_va >> 32);
radeon_emit(cs, avail_dest_va);
radeon_emit(cs, avail_dest_va >> 32);
}
assert(cs->cdw <= cdw_max);
}
}
void radv_CmdResetQueryPool(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t firstQuery,
uint32_t queryCount)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
uint64_t va = cmd_buffer->device->ws->buffer_get_va(pool->bo);
cmd_buffer->device->ws->cs_add_buffer(cmd_buffer->cs, pool->bo, 8);
si_cp_dma_clear_buffer(cmd_buffer, va + firstQuery * pool->stride,
queryCount * pool->stride, 0);
si_cp_dma_clear_buffer(cmd_buffer, va + pool->availability_offset + firstQuery * 4,
queryCount * 4, 0);
}
void radv_CmdBeginQuery(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query,
VkQueryControlFlags flags)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
struct radeon_winsys_cs *cs = cmd_buffer->cs;
uint64_t va = cmd_buffer->device->ws->buffer_get_va(pool->bo);
va += pool->stride * query;
cmd_buffer->device->ws->cs_add_buffer(cs, pool->bo, 8);
switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION:
radeon_check_space(cmd_buffer->device->ws, cs, 7);
++cmd_buffer->state.active_occlusion_queries;
if (cmd_buffer->state.active_occlusion_queries == 1)
radv_set_db_count_control(cmd_buffer);
radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 2, 0));
radeon_emit(cs, EVENT_TYPE(V_028A90_ZPASS_DONE) | EVENT_INDEX(1));
radeon_emit(cs, va);
radeon_emit(cs, va >> 32);
break;
default:
unreachable("beginning unhandled query type");
}
}
void radv_CmdEndQuery(
VkCommandBuffer commandBuffer,
VkQueryPool queryPool,
uint32_t query)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
struct radeon_winsys_cs *cs = cmd_buffer->cs;
uint64_t va = cmd_buffer->device->ws->buffer_get_va(pool->bo);
uint64_t avail_va = va + pool->availability_offset + 4 * query;
va += pool->stride * query;
cmd_buffer->device->ws->cs_add_buffer(cs, pool->bo, 8);
switch (pool->type) {
case VK_QUERY_TYPE_OCCLUSION:
radeon_check_space(cmd_buffer->device->ws, cs, 14);
cmd_buffer->state.active_occlusion_queries--;
if (cmd_buffer->state.active_occlusion_queries == 0)
radv_set_db_count_control(cmd_buffer);
radeon_emit(cs, PKT3(PKT3_EVENT_WRITE, 2, 0));
radeon_emit(cs, EVENT_TYPE(V_028A90_ZPASS_DONE) | EVENT_INDEX(1));
radeon_emit(cs, va + 8);
radeon_emit(cs, (va + 8) >> 32);
radeon_emit(cs, PKT3(PKT3_OCCLUSION_QUERY, 3, 0));
radeon_emit(cs, va);
radeon_emit(cs, va >> 32);
radeon_emit(cs, va + pool->stride - 16);
radeon_emit(cs, (va + pool->stride - 16) >> 32);
break;
default:
unreachable("ending unhandled query type");
}
radeon_check_space(cmd_buffer->device->ws, cs, 5);
radeon_emit(cs, PKT3(PKT3_WRITE_DATA, 3, 0));
radeon_emit(cs, S_370_DST_SEL(V_370_MEMORY_SYNC) |
S_370_WR_CONFIRM(1) |
S_370_ENGINE_SEL(V_370_ME));
radeon_emit(cs, avail_va);
radeon_emit(cs, avail_va >> 32);
radeon_emit(cs, 1);
}
void radv_CmdWriteTimestamp(
VkCommandBuffer commandBuffer,
VkPipelineStageFlagBits pipelineStage,
VkQueryPool queryPool,
uint32_t query)
{
RADV_FROM_HANDLE(radv_cmd_buffer, cmd_buffer, commandBuffer);
RADV_FROM_HANDLE(radv_query_pool, pool, queryPool);
struct radeon_winsys_cs *cs = cmd_buffer->cs;
uint64_t va = cmd_buffer->device->ws->buffer_get_va(pool->bo);
uint64_t avail_va = va + pool->availability_offset + 4 * query;
uint64_t query_va = va + pool->stride * query;
cmd_buffer->device->ws->cs_add_buffer(cs, pool->bo, 5);
unsigned cdw_max = radeon_check_space(cmd_buffer->device->ws, cs, 11);
radeon_emit(cs, PKT3(PKT3_EVENT_WRITE_EOP, 4, 0));
radeon_emit(cs, EVENT_TYPE(V_028A90_BOTTOM_OF_PIPE_TS) | EVENT_INDEX(5));
radeon_emit(cs, query_va);
radeon_emit(cs, (3 << 29) | ((query_va >> 32) & 0xFFFF));
radeon_emit(cs, 0);
radeon_emit(cs, 0);
radeon_emit(cs, PKT3(PKT3_WRITE_DATA, 3, 0));
radeon_emit(cs, S_370_DST_SEL(V_370_MEMORY_SYNC) |
S_370_WR_CONFIRM(1) |
S_370_ENGINE_SEL(V_370_ME));
radeon_emit(cs, avail_va);
radeon_emit(cs, avail_va >> 32);
radeon_emit(cs, 1);
assert(cmd_buffer->cs->cdw <= cdw_max);
}

View File

@ -0,0 +1,336 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* Based on radeon_winsys.h which is:
* Copyright 2008 Corbin Simpson <MostAwesomeDude@gmail.com>
* Copyright 2010 Marek Olšák <maraeo@gmail.com>
*
* 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.
*/
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include "main/macros.h"
#include "amd_family.h"
#define FREE(x) free(x)
enum radeon_bo_domain { /* bitfield */
RADEON_DOMAIN_GTT = 2,
RADEON_DOMAIN_VRAM = 4,
RADEON_DOMAIN_VRAM_GTT = RADEON_DOMAIN_VRAM | RADEON_DOMAIN_GTT
};
enum radeon_bo_flag { /* bitfield */
RADEON_FLAG_GTT_WC = (1 << 0),
RADEON_FLAG_CPU_ACCESS = (1 << 1),
RADEON_FLAG_NO_CPU_ACCESS = (1 << 2),
};
enum radeon_bo_usage { /* bitfield */
RADEON_USAGE_READ = 2,
RADEON_USAGE_WRITE = 4,
RADEON_USAGE_READWRITE = RADEON_USAGE_READ | RADEON_USAGE_WRITE
};
enum ring_type {
RING_GFX = 0,
RING_COMPUTE,
RING_DMA,
RING_UVD,
RING_VCE,
RING_LAST,
};
struct radeon_winsys_cs {
unsigned cdw; /* Number of used dwords. */
unsigned max_dw; /* Maximum number of dwords. */
uint32_t *buf; /* The base pointer of the chunk. */
};
struct radeon_info {
/* PCI info: domain:bus:dev:func */
uint32_t pci_domain;
uint32_t pci_bus;
uint32_t pci_dev;
uint32_t pci_func;
/* Device info. */
uint32_t pci_id;
enum radeon_family family;
const char *name;
enum chip_class chip_class;
uint32_t gart_page_size;
uint64_t gart_size;
uint64_t vram_size;
bool has_dedicated_vram;
bool has_virtual_memory;
bool gfx_ib_pad_with_type2;
bool has_sdma;
bool has_uvd;
uint32_t vce_fw_version;
uint32_t vce_harvest_config;
uint32_t clock_crystal_freq;
/* Kernel info. */
uint32_t drm_major; /* version */
uint32_t drm_minor;
uint32_t drm_patchlevel;
bool has_userptr;
/* Shader cores. */
uint32_t r600_max_quad_pipes; /* wave size / 16 */
uint32_t max_shader_clock;
uint32_t num_good_compute_units;
uint32_t max_se; /* shader engines */
uint32_t max_sh_per_se; /* shader arrays per shader engine */
/* Render backends (color + depth blocks). */
uint32_t r300_num_gb_pipes;
uint32_t r300_num_z_pipes;
uint32_t r600_gb_backend_map; /* R600 harvest config */
bool r600_gb_backend_map_valid;
uint32_t r600_num_banks;
uint32_t num_render_backends;
uint32_t num_tile_pipes; /* pipe count from PIPE_CONFIG */
uint32_t pipe_interleave_bytes;
uint32_t enabled_rb_mask; /* GCN harvest config */
/* Tile modes. */
uint32_t si_tile_mode_array[32];
uint32_t cik_macrotile_mode_array[16];
};
#define RADEON_SURF_MAX_LEVEL 32
#define RADEON_SURF_TYPE_MASK 0xFF
#define RADEON_SURF_TYPE_SHIFT 0
#define RADEON_SURF_TYPE_1D 0
#define RADEON_SURF_TYPE_2D 1
#define RADEON_SURF_TYPE_3D 2
#define RADEON_SURF_TYPE_CUBEMAP 3
#define RADEON_SURF_TYPE_1D_ARRAY 4
#define RADEON_SURF_TYPE_2D_ARRAY 5
#define RADEON_SURF_MODE_MASK 0xFF
#define RADEON_SURF_MODE_SHIFT 8
#define RADEON_SURF_MODE_LINEAR_ALIGNED 1
#define RADEON_SURF_MODE_1D 2
#define RADEON_SURF_MODE_2D 3
#define RADEON_SURF_SCANOUT (1 << 16)
#define RADEON_SURF_ZBUFFER (1 << 17)
#define RADEON_SURF_SBUFFER (1 << 18)
#define RADEON_SURF_Z_OR_SBUFFER (RADEON_SURF_ZBUFFER | RADEON_SURF_SBUFFER)
#define RADEON_SURF_HAS_SBUFFER_MIPTREE (1 << 19)
#define RADEON_SURF_HAS_TILE_MODE_INDEX (1 << 20)
#define RADEON_SURF_FMASK (1 << 21)
#define RADEON_SURF_DISABLE_DCC (1 << 22)
#define RADEON_SURF_GET(v, field) (((v) >> RADEON_SURF_ ## field ## _SHIFT) & RADEON_SURF_ ## field ## _MASK)
#define RADEON_SURF_SET(v, field) (((v) & RADEON_SURF_ ## field ## _MASK) << RADEON_SURF_ ## field ## _SHIFT)
#define RADEON_SURF_CLR(v, field) ((v) & ~(RADEON_SURF_ ## field ## _MASK << RADEON_SURF_ ## field ## _SHIFT))
struct radeon_surf_level {
uint64_t offset;
uint64_t slice_size;
uint32_t npix_x;
uint32_t npix_y;
uint32_t npix_z;
uint32_t nblk_x;
uint32_t nblk_y;
uint32_t nblk_z;
uint32_t pitch_bytes;
uint32_t mode;
uint64_t dcc_offset;
uint64_t dcc_fast_clear_size;
bool dcc_enabled;
};
/* surface defintions from the winsys */
struct radeon_surf {
/* These are inputs to the calculator. */
uint32_t npix_x;
uint32_t npix_y;
uint32_t npix_z;
uint32_t blk_w;
uint32_t blk_h;
uint32_t blk_d;
uint32_t array_size;
uint32_t last_level;
uint32_t bpe;
uint32_t nsamples;
uint32_t flags;
/* These are return values. Some of them can be set by the caller, but
* they will be treated as hints (e.g. bankw, bankh) and might be
* changed by the calculator.
*/
uint64_t bo_size;
uint64_t bo_alignment;
/* This applies to EG and later. */
uint32_t bankw;
uint32_t bankh;
uint32_t mtilea;
uint32_t tile_split;
uint32_t stencil_tile_split;
uint64_t stencil_offset;
struct radeon_surf_level level[RADEON_SURF_MAX_LEVEL];
struct radeon_surf_level stencil_level[RADEON_SURF_MAX_LEVEL];
uint32_t tiling_index[RADEON_SURF_MAX_LEVEL];
uint32_t stencil_tiling_index[RADEON_SURF_MAX_LEVEL];
uint32_t pipe_config;
uint32_t num_banks;
uint32_t macro_tile_index;
uint32_t micro_tile_mode; /* displayable, thin, depth, rotated */
/* Whether the depth miptree or stencil miptree as used by the DB are
* adjusted from their TC compatible form to ensure depth/stencil
* compatibility. If either is true, the corresponding plane cannot be
* sampled from.
*/
bool depth_adjusted;
bool stencil_adjusted;
uint64_t dcc_size;
uint64_t dcc_alignment;
};
enum radeon_bo_layout {
RADEON_LAYOUT_LINEAR = 0,
RADEON_LAYOUT_TILED,
RADEON_LAYOUT_SQUARETILED,
RADEON_LAYOUT_UNKNOWN
};
/* Tiling info for display code, DRI sharing, and other data. */
struct radeon_bo_metadata {
/* Tiling flags describing the texture layout for display code
* and DRI sharing.
*/
enum radeon_bo_layout microtile;
enum radeon_bo_layout macrotile;
unsigned pipe_config;
unsigned bankw;
unsigned bankh;
unsigned tile_split;
unsigned mtilea;
unsigned num_banks;
unsigned stride;
bool scanout;
/* Additional metadata associated with the buffer, in bytes.
* The maximum size is 64 * 4. This is opaque for the winsys & kernel.
* Supported by amdgpu only.
*/
uint32_t size_metadata;
uint32_t metadata[64];
};
struct radeon_winsys_bo;
struct radeon_winsys_fence;
struct radeon_winsys {
void (*destroy)(struct radeon_winsys *ws);
void (*query_info)(struct radeon_winsys *ws,
struct radeon_info *info);
struct radeon_winsys_bo *(*buffer_create)(struct radeon_winsys *ws,
uint64_t size,
unsigned alignment,
enum radeon_bo_domain domain,
enum radeon_bo_flag flags);
void (*buffer_destroy)(struct radeon_winsys_bo *bo);
void *(*buffer_map)(struct radeon_winsys_bo *bo);
struct radeon_winsys_bo *(*buffer_from_fd)(struct radeon_winsys *ws,
int fd,
unsigned *stride, unsigned *offset);
bool (*buffer_get_fd)(struct radeon_winsys *ws,
struct radeon_winsys_bo *bo,
int *fd);
void (*buffer_unmap)(struct radeon_winsys_bo *bo);
uint64_t (*buffer_get_va)(struct radeon_winsys_bo *bo);
void (*buffer_set_metadata)(struct radeon_winsys_bo *bo,
struct radeon_bo_metadata *md);
struct radeon_winsys_ctx *(*ctx_create)(struct radeon_winsys *ws);
void (*ctx_destroy)(struct radeon_winsys_ctx *ctx);
bool (*ctx_wait_idle)(struct radeon_winsys_ctx *ctx);
struct radeon_winsys_cs *(*cs_create)(struct radeon_winsys *ws,
enum ring_type ring_type);
void (*cs_destroy)(struct radeon_winsys_cs *cs);
void (*cs_reset)(struct radeon_winsys_cs *cs);
bool (*cs_finalize)(struct radeon_winsys_cs *cs);
void (*cs_grow)(struct radeon_winsys_cs * cs, size_t min_size);
int (*cs_submit)(struct radeon_winsys_ctx *ctx,
struct radeon_winsys_cs **cs_array,
unsigned cs_count,
bool can_patch,
struct radeon_winsys_fence *fence);
void (*cs_add_buffer)(struct radeon_winsys_cs *cs,
struct radeon_winsys_bo *bo,
uint8_t priority);
void (*cs_execute_secondary)(struct radeon_winsys_cs *parent,
struct radeon_winsys_cs *child);
int (*surface_init)(struct radeon_winsys *ws,
struct radeon_surf *surf);
int (*surface_best)(struct radeon_winsys *ws,
struct radeon_surf *surf);
struct radeon_winsys_fence *(*create_fence)();
void (*destroy_fence)(struct radeon_winsys_fence *fence);
bool (*fence_wait)(struct radeon_winsys *ws,
struct radeon_winsys_fence *fence,
bool absolute,
uint64_t timeout);
};
static inline void radeon_emit(struct radeon_winsys_cs *cs, uint32_t value)
{
cs->buf[cs->cdw++] = value;
}
static inline void radeon_emit_array(struct radeon_winsys_cs *cs,
const uint32_t *values, unsigned count)
{
memcpy(cs->buf + cs->cdw, values, count * 4);
cs->cdw += count;
}

204
src/amd/vulkan/radv_util.c Normal file
View File

@ -0,0 +1,204 @@
/*
* Copyright © 2015 Intel 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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "radv_private.h"
#include "util/u_math.h"
/** Log an error message. */
void radv_printflike(1, 2)
radv_loge(const char *format, ...)
{
va_list va;
va_start(va, format);
radv_loge_v(format, va);
va_end(va);
}
/** \see radv_loge() */
void
radv_loge_v(const char *format, va_list va)
{
fprintf(stderr, "vk: error: ");
vfprintf(stderr, format, va);
fprintf(stderr, "\n");
}
void radv_printflike(3, 4)
__radv_finishme(const char *file, int line, const char *format, ...)
{
va_list ap;
char buffer[256];
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
fprintf(stderr, "%s:%d: FINISHME: %s\n", file, line, buffer);
}
void radv_noreturn radv_printflike(1, 2)
radv_abortf(const char *format, ...)
{
va_list va;
va_start(va, format);
radv_abortfv(format, va);
va_end(va);
}
void radv_noreturn
radv_abortfv(const char *format, va_list va)
{
fprintf(stderr, "vk: error: ");
vfprintf(stderr, format, va);
fprintf(stderr, "\n");
abort();
}
VkResult
__vk_errorf(VkResult error, const char *file, int line, const char *format, ...)
{
va_list ap;
char buffer[256];
#define ERROR_CASE(error) case error: error_str = #error; break;
const char *error_str;
switch ((int32_t)error) {
/* Core errors */
ERROR_CASE(VK_ERROR_OUT_OF_HOST_MEMORY)
ERROR_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY)
ERROR_CASE(VK_ERROR_INITIALIZATION_FAILED)
ERROR_CASE(VK_ERROR_DEVICE_LOST)
ERROR_CASE(VK_ERROR_MEMORY_MAP_FAILED)
ERROR_CASE(VK_ERROR_LAYER_NOT_PRESENT)
ERROR_CASE(VK_ERROR_EXTENSION_NOT_PRESENT)
ERROR_CASE(VK_ERROR_INCOMPATIBLE_DRIVER)
/* Extension errors */
ERROR_CASE(VK_ERROR_OUT_OF_DATE_KHR)
default:
assert(!"Unknown error");
error_str = "unknown error";
}
#undef ERROR_CASE
if (format) {
va_start(ap, format);
vsnprintf(buffer, sizeof(buffer), format, ap);
va_end(ap);
fprintf(stderr, "%s:%d: %s (%s)\n", file, line, buffer, error_str);
} else {
fprintf(stderr, "%s:%d: %s\n", file, line, error_str);
}
return error;
}
int
radv_vector_init(struct radv_vector *vector, uint32_t element_size, uint32_t size)
{
assert(util_is_power_of_two(size));
assert(element_size < size && util_is_power_of_two(element_size));
vector->head = 0;
vector->tail = 0;
vector->element_size = element_size;
vector->size = size;
vector->data = malloc(size);
return vector->data != NULL;
}
void *
radv_vector_add(struct radv_vector *vector)
{
uint32_t offset, size, split, src_tail, dst_tail;
void *data;
if (vector->head - vector->tail == vector->size) {
size = vector->size * 2;
data = malloc(size);
if (data == NULL)
return NULL;
src_tail = vector->tail & (vector->size - 1);
dst_tail = vector->tail & (size - 1);
if (src_tail == 0) {
/* Since we know that the vector is full, this means that it's
* linear from start to end so we can do one copy.
*/
memcpy(data + dst_tail, vector->data, vector->size);
} else {
/* In this case, the vector is split into two pieces and we have
* to do two copies. We have to be careful to make sure each
* piece goes to the right locations. Thanks to the change in
* size, it may or may not still wrap around.
*/
split = align_u32(vector->tail, vector->size);
assert(vector->tail <= split && split < vector->head);
memcpy(data + dst_tail, vector->data + src_tail,
split - vector->tail);
memcpy(data + (split & (size - 1)), vector->data,
vector->head - split);
}
free(vector->data);
vector->data = data;
vector->size = size;
}
assert(vector->head - vector->tail < vector->size);
offset = vector->head & (vector->size - 1);
vector->head += vector->element_size;
return vector->data + offset;
}
void *
radv_vector_remove(struct radv_vector *vector)
{
uint32_t offset;
if (vector->head == vector->tail)
return NULL;
assert(vector->head - vector->tail <= vector->size);
offset = vector->tail & (vector->size - 1);
vector->tail += vector->element_size;
return vector->data + offset;
}

View File

@ -0,0 +1,9 @@
#pragma once
#ifdef HAVE___BUILTIN_POPCOUNT
#define util_bitcount(i) __builtin_popcount(i)
#else
extern unsigned int
util_bitcount(unsigned int n);
#endif

246
src/amd/vulkan/radv_wsi.c Normal file
View File

@ -0,0 +1,246 @@
/*
* Copyright © 2016 Red Hat
* based on intel anv code:
* Copyright © 2015 Intel 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 "radv_wsi.h"
VkResult
radv_init_wsi(struct radv_physical_device *physical_device)
{
VkResult result;
memset(physical_device->wsi, 0, sizeof(physical_device->wsi));
#ifdef VK_USE_PLATFORM_XCB_KHR
result = radv_x11_init_wsi(physical_device);
if (result != VK_SUCCESS)
return result;
#endif
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
result = radv_wl_init_wsi(physical_device);
if (result != VK_SUCCESS) {
#ifdef VK_USE_PLATFORM_XCB_KHR
radv_x11_finish_wsi(physical_device);
#endif
return result;
}
#endif
return VK_SUCCESS;
}
void
radv_finish_wsi(struct radv_physical_device *physical_device)
{
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
radv_wl_finish_wsi(physical_device);
#endif
#ifdef VK_USE_PLATFORM_XCB_KHR
radv_x11_finish_wsi(physical_device);
#endif
}
void radv_DestroySurfaceKHR(
VkInstance _instance,
VkSurfaceKHR _surface,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_instance, instance, _instance);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, _surface);
radv_free2(&instance->alloc, pAllocator, surface);
}
VkResult radv_GetPhysicalDeviceSurfaceSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
VkSurfaceKHR _surface,
VkBool32* pSupported)
{
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, _surface);
struct radv_wsi_interface *iface = device->wsi[surface->platform];
return iface->get_support(surface, device, queueFamilyIndex, pSupported);
}
VkResult radv_GetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR _surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
{
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, _surface);
struct radv_wsi_interface *iface = device->wsi[surface->platform];
return iface->get_capabilities(surface, device, pSurfaceCapabilities);
}
VkResult radv_GetPhysicalDeviceSurfaceFormatsKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR _surface,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormatKHR* pSurfaceFormats)
{
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, _surface);
struct radv_wsi_interface *iface = device->wsi[surface->platform];
return iface->get_formats(surface, device, pSurfaceFormatCount,
pSurfaceFormats);
}
VkResult radv_GetPhysicalDeviceSurfacePresentModesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR _surface,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes)
{
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, _surface);
struct radv_wsi_interface *iface = device->wsi[surface->platform];
return iface->get_present_modes(surface, device, pPresentModeCount,
pPresentModes);
}
VkResult radv_CreateSwapchainKHR(
VkDevice _device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSwapchainKHR* pSwapchain)
{
RADV_FROM_HANDLE(radv_device, device, _device);
RADV_FROM_HANDLE(_VkIcdSurfaceBase, surface, pCreateInfo->surface);
struct radv_wsi_interface *iface =
device->instance->physicalDevice.wsi[surface->platform];
struct radv_swapchain *swapchain;
VkResult result = iface->create_swapchain(surface, device, pCreateInfo,
pAllocator, &swapchain);
if (result != VK_SUCCESS)
return result;
if (pAllocator)
swapchain->alloc = *pAllocator;
else
swapchain->alloc = device->alloc;
for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++)
swapchain->fences[i] = VK_NULL_HANDLE;
*pSwapchain = radv_swapchain_to_handle(swapchain);
return VK_SUCCESS;
}
void radv_DestroySwapchainKHR(
VkDevice device,
VkSwapchainKHR _swapchain,
const VkAllocationCallbacks* pAllocator)
{
RADV_FROM_HANDLE(radv_swapchain, swapchain, _swapchain);
for (unsigned i = 0; i < ARRAY_SIZE(swapchain->fences); i++) {
if (swapchain->fences[i] != VK_NULL_HANDLE)
radv_DestroyFence(device, swapchain->fences[i], pAllocator);
}
swapchain->destroy(swapchain, pAllocator);
}
VkResult radv_GetSwapchainImagesKHR(
VkDevice device,
VkSwapchainKHR _swapchain,
uint32_t* pSwapchainImageCount,
VkImage* pSwapchainImages)
{
RADV_FROM_HANDLE(radv_swapchain, swapchain, _swapchain);
return swapchain->get_images(swapchain, pSwapchainImageCount,
pSwapchainImages);
}
VkResult radv_AcquireNextImageKHR(
VkDevice device,
VkSwapchainKHR _swapchain,
uint64_t timeout,
VkSemaphore semaphore,
VkFence fence,
uint32_t* pImageIndex)
{
RADV_FROM_HANDLE(radv_swapchain, swapchain, _swapchain);
return swapchain->acquire_next_image(swapchain, timeout, semaphore,
pImageIndex);
}
VkResult radv_QueuePresentKHR(
VkQueue _queue,
const VkPresentInfoKHR* pPresentInfo)
{
RADV_FROM_HANDLE(radv_queue, queue, _queue);
VkResult result = VK_SUCCESS;
for (uint32_t i = 0; i < pPresentInfo->swapchainCount; i++) {
RADV_FROM_HANDLE(radv_swapchain, swapchain, pPresentInfo->pSwapchains[i]);
assert(swapchain->device == queue->device);
if (swapchain->fences[0] == VK_NULL_HANDLE) {
result = radv_CreateFence(radv_device_to_handle(queue->device),
&(VkFenceCreateInfo) {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = 0,
}, &swapchain->alloc, &swapchain->fences[0]);
if (result != VK_SUCCESS)
return result;
} else {
radv_ResetFences(radv_device_to_handle(queue->device),
1, &swapchain->fences[0]);
}
radv_QueueSubmit(_queue, 0, NULL, swapchain->fences[0]);
result = swapchain->queue_present(swapchain, queue,
pPresentInfo->pImageIndices[i]);
/* TODO: What if one of them returns OUT_OF_DATE? */
if (result != VK_SUCCESS)
return result;
VkFence last = swapchain->fences[2];
swapchain->fences[2] = swapchain->fences[1];
swapchain->fences[1] = swapchain->fences[0];
swapchain->fences[0] = last;
if (last != VK_NULL_HANDLE) {
radv_WaitForFences(radv_device_to_handle(queue->device),
1, &last, true, 1);
}
}
return VK_SUCCESS;
}

79
src/amd/vulkan/radv_wsi.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright © 2016 Red Hat
* based on intel anv code:
* Copyright © 2015 Intel 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.
*/
#pragma once
#include "radv_private.h"
struct radv_swapchain;
struct radv_wsi_interface {
VkResult (*get_support)(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t queueFamilyIndex,
VkBool32* pSupported);
VkResult (*get_capabilities)(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
VkResult (*get_formats)(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormatKHR* pSurfaceFormats);
VkResult (*get_present_modes)(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes);
VkResult (*create_swapchain)(VkIcdSurfaceBase *surface,
struct radv_device *device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct radv_swapchain **swapchain);
};
struct radv_swapchain {
struct radv_device *device;
VkAllocationCallbacks alloc;
VkFence fences[3];
VkResult (*destroy)(struct radv_swapchain *swapchain,
const VkAllocationCallbacks *pAllocator);
VkResult (*get_images)(struct radv_swapchain *swapchain,
uint32_t *pCount, VkImage *pSwapchainImages);
VkResult (*acquire_next_image)(struct radv_swapchain *swap_chain,
uint64_t timeout, VkSemaphore semaphore,
uint32_t *image_index);
VkResult (*queue_present)(struct radv_swapchain *swap_chain,
struct radv_queue *queue,
uint32_t image_index);
};
RADV_DEFINE_NONDISP_HANDLE_CASTS(_VkIcdSurfaceBase, VkSurfaceKHR)
RADV_DEFINE_NONDISP_HANDLE_CASTS(radv_swapchain, VkSwapchainKHR)
VkResult radv_x11_init_wsi(struct radv_physical_device *physical_device);
void radv_x11_finish_wsi(struct radv_physical_device *physical_device);
VkResult radv_wl_init_wsi(struct radv_physical_device *physical_device);
void radv_wl_finish_wsi(struct radv_physical_device *physical_device);

View File

@ -0,0 +1,880 @@
/*
* Copyright © 2016 Red Hat
* based on intel anv code:
* Copyright © 2015 Intel 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 <wayland-client.h>
#include <wayland-drm-client-protocol.h>
#include "radv_wsi.h"
#include "vk_format.h"
#include <util/hash_table.h>
#define MIN_NUM_IMAGES 2
struct wsi_wl_display {
struct radv_physical_device *physical_device;
struct wl_display * display;
struct wl_drm * drm;
/* Vector of VkFormats supported */
struct radv_vector formats;
uint32_t capabilities;
};
struct wsi_wayland {
struct radv_wsi_interface base;
struct radv_physical_device * physical_device;
pthread_mutex_t mutex;
/* Hash table of wl_display -> wsi_wl_display mappings */
struct hash_table * displays;
};
static void
wsi_wl_display_add_vk_format(struct wsi_wl_display *display, VkFormat format)
{
/* Don't add a format that's already in the list */
VkFormat *f;
radv_vector_foreach(f, &display->formats)
if (*f == format)
return;
/* Don't add formats that aren't renderable. */
VkFormatProperties props;
radv_GetPhysicalDeviceFormatProperties(
radv_physical_device_to_handle(display->physical_device), format, &props);
if (!(props.optimalTilingFeatures & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT))
return;
f = radv_vector_add(&display->formats);
if (f)
*f = format;
}
static void
drm_handle_device(void *data, struct wl_drm *drm, const char *name)
{
fprintf(stderr, "wl_drm.device(%s)\n", name);
}
static uint32_t
wl_drm_format_for_vk_format(VkFormat vk_format, bool alpha)
{
switch (vk_format) {
/* TODO: Figure out what all the formats mean and make this table
* correct.
*/
#if 0
case VK_FORMAT_R4G4B4A4_UNORM:
return alpha ? WL_DRM_FORMAT_ABGR4444 : WL_DRM_FORMAT_XBGR4444;
case VK_FORMAT_R5G6B5_UNORM:
return WL_DRM_FORMAT_BGR565;
case VK_FORMAT_R5G5B5A1_UNORM:
return alpha ? WL_DRM_FORMAT_ABGR1555 : WL_DRM_FORMAT_XBGR1555;
case VK_FORMAT_R8G8B8_UNORM:
return WL_DRM_FORMAT_XBGR8888;
case VK_FORMAT_R8G8B8A8_UNORM:
return alpha ? WL_DRM_FORMAT_ABGR8888 : WL_DRM_FORMAT_XBGR8888;
case VK_FORMAT_R10G10B10A2_UNORM:
return alpha ? WL_DRM_FORMAT_ABGR2101010 : WL_DRM_FORMAT_XBGR2101010;
case VK_FORMAT_B4G4R4A4_UNORM:
return alpha ? WL_DRM_FORMAT_ARGB4444 : WL_DRM_FORMAT_XRGB4444;
case VK_FORMAT_B5G6R5_UNORM:
return WL_DRM_FORMAT_RGB565;
case VK_FORMAT_B5G5R5A1_UNORM:
return alpha ? WL_DRM_FORMAT_XRGB1555 : WL_DRM_FORMAT_XRGB1555;
#endif
case VK_FORMAT_B8G8R8_SRGB:
return WL_DRM_FORMAT_BGRX8888;
case VK_FORMAT_B8G8R8A8_SRGB:
return alpha ? WL_DRM_FORMAT_ARGB8888 : WL_DRM_FORMAT_XRGB8888;
#if 0
case VK_FORMAT_B10G10R10A2_UNORM:
return alpha ? WL_DRM_FORMAT_ARGB2101010 : WL_DRM_FORMAT_XRGB2101010;
#endif
default:
assert(!"Unsupported Vulkan format");
return 0;
}
}
static void
drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format)
{
struct wsi_wl_display *display = data;
switch (wl_format) {
#if 0
case WL_DRM_FORMAT_ABGR4444:
case WL_DRM_FORMAT_XBGR4444:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R4G4B4A4_UNORM);
break;
case WL_DRM_FORMAT_BGR565:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G6B5_UNORM);
break;
case WL_DRM_FORMAT_ABGR1555:
case WL_DRM_FORMAT_XBGR1555:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R5G5B5A1_UNORM);
break;
case WL_DRM_FORMAT_XBGR8888:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8_UNORM);
/* fallthrough */
case WL_DRM_FORMAT_ABGR8888:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R8G8B8A8_UNORM);
break;
case WL_DRM_FORMAT_ABGR2101010:
case WL_DRM_FORMAT_XBGR2101010:
wsi_wl_display_add_vk_format(display, VK_FORMAT_R10G10B10A2_UNORM);
break;
case WL_DRM_FORMAT_ARGB4444:
case WL_DRM_FORMAT_XRGB4444:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B4G4R4A4_UNORM);
break;
case WL_DRM_FORMAT_RGB565:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G6R5_UNORM);
break;
case WL_DRM_FORMAT_ARGB1555:
case WL_DRM_FORMAT_XRGB1555:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B5G5R5A1_UNORM);
break;
#endif
case WL_DRM_FORMAT_XRGB8888:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8_SRGB);
/* fallthrough */
case WL_DRM_FORMAT_ARGB8888:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B8G8R8A8_SRGB);
break;
#if 0
case WL_DRM_FORMAT_ARGB2101010:
case WL_DRM_FORMAT_XRGB2101010:
wsi_wl_display_add_vk_format(display, VK_FORMAT_B10G10R10A2_UNORM);
break;
#endif
}
}
static void
drm_handle_authenticated(void *data, struct wl_drm *drm)
{
}
static void
drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities)
{
struct wsi_wl_display *display = data;
display->capabilities = capabilities;
}
static const struct wl_drm_listener drm_listener = {
drm_handle_device,
drm_handle_format,
drm_handle_authenticated,
drm_handle_capabilities,
};
static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
struct wsi_wl_display *display = data;
if (strcmp(interface, "wl_drm") == 0) {
assert(display->drm == NULL);
assert(version >= 2);
display->drm = wl_registry_bind(registry, name, &wl_drm_interface, 2);
if (display->drm)
wl_drm_add_listener(display->drm, &drm_listener, display);
}
}
static void
registry_handle_global_remove(void *data, struct wl_registry *registry,
uint32_t name)
{ /* No-op */ }
static const struct wl_registry_listener registry_listener = {
registry_handle_global,
registry_handle_global_remove
};
static void
wsi_wl_display_destroy(struct wsi_wayland *wsi, struct wsi_wl_display *display)
{
radv_vector_finish(&display->formats);
if (display->drm)
wl_drm_destroy(display->drm);
radv_free(&wsi->physical_device->instance->alloc, display);
}
static struct wsi_wl_display *
wsi_wl_display_create(struct wsi_wayland *wsi, struct wl_display *wl_display)
{
struct wsi_wl_display *display =
radv_alloc(&wsi->physical_device->instance->alloc, sizeof(*display), 8,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!display)
return NULL;
memset(display, 0, sizeof(*display));
display->display = wl_display;
display->physical_device = wsi->physical_device;
if (!radv_vector_init(&display->formats, sizeof(VkFormat), 8))
goto fail;
struct wl_registry *registry = wl_display_get_registry(wl_display);
if (!registry)
return NULL;
wl_registry_add_listener(registry, &registry_listener, display);
/* Round-rip to get the wl_drm global */
wl_display_roundtrip(wl_display);
if (!display->drm)
goto fail;
/* Round-rip to get wl_drm formats and capabilities */
wl_display_roundtrip(wl_display);
/* We need prime support */
if (!(display->capabilities & WL_DRM_CAPABILITY_PRIME))
goto fail;
/* We don't need this anymore */
wl_registry_destroy(registry);
return display;
fail:
if (registry)
wl_registry_destroy(registry);
wsi_wl_display_destroy(wsi, display);
return NULL;
}
static struct wsi_wl_display *
wsi_wl_get_display(struct radv_physical_device *device,
struct wl_display *wl_display)
{
struct wsi_wayland *wsi =
(struct wsi_wayland *)device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
pthread_mutex_lock(&wsi->mutex);
struct hash_entry *entry = _mesa_hash_table_search(wsi->displays,
wl_display);
if (!entry) {
/* We're about to make a bunch of blocking calls. Let's drop the
* mutex for now so we don't block up too badly.
*/
pthread_mutex_unlock(&wsi->mutex);
struct wsi_wl_display *display = wsi_wl_display_create(wsi, wl_display);
pthread_mutex_lock(&wsi->mutex);
entry = _mesa_hash_table_search(wsi->displays, wl_display);
if (entry) {
/* Oops, someone raced us to it */
wsi_wl_display_destroy(wsi, display);
} else {
entry = _mesa_hash_table_insert(wsi->displays, wl_display, display);
}
}
pthread_mutex_unlock(&wsi->mutex);
return entry->data;
}
VkBool32 radv_GetPhysicalDeviceWaylandPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
struct wl_display* display)
{
RADV_FROM_HANDLE(radv_physical_device, physical_device, physicalDevice);
return wsi_wl_get_display(physical_device, display) != NULL;
}
static VkResult
wsi_wl_surface_get_support(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t queueFamilyIndex,
VkBool32* pSupported)
{
*pSupported = true;
return VK_SUCCESS;
}
static const VkPresentModeKHR present_modes[] = {
VK_PRESENT_MODE_MAILBOX_KHR,
VK_PRESENT_MODE_FIFO_KHR,
};
static VkResult
wsi_wl_surface_get_capabilities(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
VkSurfaceCapabilitiesKHR* caps)
{
caps->minImageCount = MIN_NUM_IMAGES;
caps->maxImageCount = 4;
caps->currentExtent = (VkExtent2D) { -1, -1 };
caps->minImageExtent = (VkExtent2D) { 1, 1 };
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
caps->maxImageArrayLayers = 1;
caps->supportedCompositeAlpha =
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
caps->supportedUsageFlags =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
return VK_SUCCESS;
}
static VkResult
wsi_wl_surface_get_formats(VkIcdSurfaceBase *icd_surface,
struct radv_physical_device *device,
uint32_t* pSurfaceFormatCount,
VkSurfaceFormatKHR* pSurfaceFormats)
{
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
struct wsi_wl_display *display =
wsi_wl_get_display(device, surface->display);
uint32_t count = radv_vector_length(&display->formats);
if (pSurfaceFormats == NULL) {
*pSurfaceFormatCount = count;
return VK_SUCCESS;
}
assert(*pSurfaceFormatCount >= count);
*pSurfaceFormatCount = count;
VkFormat *f;
radv_vector_foreach(f, &display->formats) {
*(pSurfaceFormats++) = (VkSurfaceFormatKHR) {
.format = *f,
/* TODO: We should get this from the compositor somehow */
.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR,
};
}
return VK_SUCCESS;
}
static VkResult
wsi_wl_surface_get_present_modes(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t* pPresentModeCount,
VkPresentModeKHR* pPresentModes)
{
if (pPresentModes == NULL) {
*pPresentModeCount = ARRAY_SIZE(present_modes);
return VK_SUCCESS;
}
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
*pPresentModeCount = ARRAY_SIZE(present_modes);
return VK_SUCCESS;
}
static VkResult
wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *surface,
struct radv_device *device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct radv_swapchain **swapchain);
VkResult radv_CreateWaylandSurfaceKHR(
VkInstance _instance,
const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
RADV_FROM_HANDLE(radv_instance, instance, _instance);
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR);
VkIcdSurfaceWayland *surface;
surface = radv_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (surface == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
surface->base.platform = VK_ICD_WSI_PLATFORM_WAYLAND;
surface->display = pCreateInfo->display;
surface->surface = pCreateInfo->surface;
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
return VK_SUCCESS;
}
struct wsi_wl_image {
struct radv_image * image;
struct radv_device_memory * memory;
struct wl_buffer * buffer;
bool busy;
};
struct wsi_wl_swapchain {
struct radv_swapchain base;
struct wsi_wl_display * display;
struct wl_event_queue * queue;
struct wl_surface * surface;
VkExtent2D extent;
VkFormat vk_format;
uint32_t drm_format;
VkPresentModeKHR present_mode;
bool fifo_ready;
uint32_t image_count;
struct wsi_wl_image images[0];
};
static VkResult
wsi_wl_swapchain_get_images(struct radv_swapchain *radv_chain,
uint32_t *pCount, VkImage *pSwapchainImages)
{
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)radv_chain;
if (pSwapchainImages == NULL) {
*pCount = chain->image_count;
return VK_SUCCESS;
}
assert(chain->image_count <= *pCount);
for (uint32_t i = 0; i < chain->image_count; i++)
pSwapchainImages[i] = radv_image_to_handle(chain->images[i].image);
*pCount = chain->image_count;
return VK_SUCCESS;
}
static VkResult
wsi_wl_swapchain_acquire_next_image(struct radv_swapchain *radv_chain,
uint64_t timeout,
VkSemaphore semaphore,
uint32_t *image_index)
{
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)radv_chain;
int ret = wl_display_dispatch_queue_pending(chain->display->display,
chain->queue);
/* XXX: I'm not sure if out-of-date is the right error here. If
* wl_display_dispatch_queue_pending fails it most likely means we got
* kicked by the server so this seems more-or-less correct.
*/
if (ret < 0)
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
while (1) {
for (uint32_t i = 0; i < chain->image_count; i++) {
if (!chain->images[i].busy) {
/* We found a non-busy image */
*image_index = i;
return VK_SUCCESS;
}
}
/* This time we do a blocking dispatch because we can't go
* anywhere until we get an event.
*/
int ret = wl_display_roundtrip_queue(chain->display->display,
chain->queue);
if (ret < 0)
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
}
}
static void
frame_handle_done(void *data, struct wl_callback *callback, uint32_t serial)
{
struct wsi_wl_swapchain *chain = data;
chain->fifo_ready = true;
wl_callback_destroy(callback);
}
static const struct wl_callback_listener frame_listener = {
frame_handle_done,
};
static VkResult
wsi_wl_swapchain_queue_present(struct radv_swapchain *radv_chain,
struct radv_queue *queue,
uint32_t image_index)
{
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)radv_chain;
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
while (!chain->fifo_ready) {
int ret = wl_display_dispatch_queue(chain->display->display,
chain->queue);
if (ret < 0)
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
}
}
assert(image_index < chain->image_count);
wl_surface_attach(chain->surface, chain->images[image_index].buffer, 0, 0);
wl_surface_damage(chain->surface, 0, 0, INT32_MAX, INT32_MAX);
if (chain->present_mode == VK_PRESENT_MODE_FIFO_KHR) {
struct wl_callback *frame = wl_surface_frame(chain->surface);
wl_proxy_set_queue((struct wl_proxy *)frame, chain->queue);
wl_callback_add_listener(frame, &frame_listener, chain);
chain->fifo_ready = false;
}
chain->images[image_index].busy = true;
wl_surface_commit(chain->surface);
wl_display_flush(chain->display->display);
return VK_SUCCESS;
}
static void
wsi_wl_image_finish(struct wsi_wl_swapchain *chain, struct wsi_wl_image *image,
const VkAllocationCallbacks* pAllocator)
{
VkDevice vk_device = radv_device_to_handle(chain->base.device);
radv_FreeMemory(vk_device, radv_device_memory_to_handle(image->memory),
pAllocator);
radv_DestroyImage(vk_device, radv_image_to_handle(image->image),
pAllocator);
}
static void
buffer_handle_release(void *data, struct wl_buffer *buffer)
{
struct wsi_wl_image *image = data;
assert(image->buffer == buffer);
image->busy = false;
}
static const struct wl_buffer_listener buffer_listener = {
buffer_handle_release,
};
static VkResult
wsi_wl_image_init(struct wsi_wl_swapchain *chain,
struct wsi_wl_image *image,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks* pAllocator)
{
VkDevice vk_device = radv_device_to_handle(chain->base.device);
VkResult result;
bool bret;
VkImage vk_image;
struct radeon_surf *surface;
int fd;
result = radv_image_create(vk_device,
&(struct radv_image_create_info) {
.vk_info =
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = chain->vk_format,
.extent = {
.width = chain->extent.width,
.height = chain->extent.height,
.depth = 1
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = 1,
/* FIXME: Need a way to use X tiling to allow scanout */
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
pCreateInfo->imageUsage),
.flags = 0,
},
.scanout = true},
pAllocator,
&vk_image);
if (result != VK_SUCCESS)
return result;
image->image = radv_image_from_handle(vk_image);
assert(vk_format_is_color(image->image->vk_format));
VkDeviceMemory vk_memory;
result = radv_AllocateMemory(vk_device,
&(VkMemoryAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = image->image->size,
.memoryTypeIndex = 0,
},
pAllocator,
&vk_memory);
if (result != VK_SUCCESS)
goto fail_image;
image->memory = radv_device_memory_from_handle(vk_memory);
result = radv_BindImageMemory(vk_device, vk_image, vk_memory, 0);
if (result != VK_SUCCESS)
goto fail_mem;
bret = chain->base.device->ws->buffer_get_fd(chain->base.device->ws,
image->memory->bo, &fd);
if (bret == false)
goto fail_mem;
{
struct radeon_bo_metadata metadata;
radv_init_metadata(chain->base.device, image->image, &metadata);
chain->base.device->ws->buffer_set_metadata(image->memory->bo, &metadata);
}
surface = &image->image->surface;
image->buffer = wl_drm_create_prime_buffer(chain->display->drm,
fd, /* name */
chain->extent.width,
chain->extent.height,
chain->drm_format,
surface->level[0].offset,
surface->level[0].pitch_bytes,
0, 0, 0, 0 /* unused */);
wl_display_roundtrip(chain->display->display);
close(fd);
wl_proxy_set_queue((struct wl_proxy *)image->buffer, chain->queue);
wl_buffer_add_listener(image->buffer, &buffer_listener, image);
return VK_SUCCESS;
fail_mem:
radv_FreeMemory(vk_device, vk_memory, pAllocator);
fail_image:
radv_DestroyImage(vk_device, vk_image, pAllocator);
return result;
}
static VkResult
wsi_wl_swapchain_destroy(struct radv_swapchain *radv_chain,
const VkAllocationCallbacks *pAllocator)
{
struct wsi_wl_swapchain *chain = (struct wsi_wl_swapchain *)radv_chain;
for (uint32_t i = 0; i < chain->image_count; i++) {
if (chain->images[i].buffer)
wsi_wl_image_finish(chain, &chain->images[i], pAllocator);
}
radv_free2(&chain->base.device->alloc, pAllocator, chain);
return VK_SUCCESS;
}
static VkResult
wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
struct radv_device *device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct radv_swapchain **swapchain_out)
{
VkIcdSurfaceWayland *surface = (VkIcdSurfaceWayland *)icd_surface;
struct wsi_wl_swapchain *chain;
VkResult result;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
int num_images = pCreateInfo->minImageCount;
assert(num_images >= MIN_NUM_IMAGES);
/* For true mailbox mode, we need at least 4 images:
* 1) One to scan out from
* 2) One to have queued for scan-out
* 3) One to be currently held by the Wayland compositor
* 4) One to render to
*/
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
num_images = MAX2(num_images, 4);
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
chain = radv_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (chain == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
chain->base.device = device;
chain->base.destroy = wsi_wl_swapchain_destroy;
chain->base.get_images = wsi_wl_swapchain_get_images;
chain->base.acquire_next_image = wsi_wl_swapchain_acquire_next_image;
chain->base.queue_present = wsi_wl_swapchain_queue_present;
chain->surface = surface->surface;
chain->extent = pCreateInfo->imageExtent;
chain->vk_format = pCreateInfo->imageFormat;
chain->drm_format = wl_drm_format_for_vk_format(chain->vk_format, false);
chain->present_mode = pCreateInfo->presentMode;
chain->fifo_ready = true;
chain->image_count = num_images;
/* Mark a bunch of stuff as NULL. This way we can just call
* destroy_swapchain for cleanup.
*/
for (uint32_t i = 0; i < chain->image_count; i++)
chain->images[i].buffer = NULL;
chain->queue = NULL;
chain->display = wsi_wl_get_display(&device->instance->physicalDevice,
surface->display);
if (!chain->display) {
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
goto fail;
}
chain->queue = wl_display_create_queue(chain->display->display);
if (!chain->queue) {
result = vk_error(VK_ERROR_INITIALIZATION_FAILED);
goto fail;
}
for (uint32_t i = 0; i < chain->image_count; i++) {
result = wsi_wl_image_init(chain, &chain->images[i],
pCreateInfo, pAllocator);
if (result != VK_SUCCESS)
goto fail;
chain->images[i].busy = false;
}
*swapchain_out = &chain->base;
return VK_SUCCESS;
fail:
wsi_wl_swapchain_destroy(&chain->base, pAllocator);
return result;
}
VkResult
radv_wl_init_wsi(struct radv_physical_device *device)
{
struct wsi_wayland *wsi;
VkResult result;
wsi = radv_alloc(&device->instance->alloc, sizeof(*wsi), 8,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!wsi) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail;
}
wsi->physical_device = device;
int ret = pthread_mutex_init(&wsi->mutex, NULL);
if (ret != 0) {
if (ret == ENOMEM) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
} else {
/* FINISHME: Choose a better error. */
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
}
goto fail_alloc;
}
wsi->displays = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
if (!wsi->displays) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_mutex;
}
wsi->base.get_support = wsi_wl_surface_get_support;
wsi->base.get_capabilities = wsi_wl_surface_get_capabilities;
wsi->base.get_formats = wsi_wl_surface_get_formats;
wsi->base.get_present_modes = wsi_wl_surface_get_present_modes;
wsi->base.create_swapchain = wsi_wl_surface_create_swapchain;
device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = &wsi->base;
return VK_SUCCESS;
fail_mutex:
pthread_mutex_destroy(&wsi->mutex);
fail_alloc:
radv_free(&device->instance->alloc, wsi);
fail:
device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND] = NULL;
return result;
}
void
radv_wl_finish_wsi(struct radv_physical_device *device)
{
struct wsi_wayland *wsi =
(struct wsi_wayland *)device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND];
if (wsi) {
_mesa_hash_table_destroy(wsi->displays, NULL);
pthread_mutex_destroy(&wsi->mutex);
radv_free(&device->instance->alloc, wsi);
}
}

View File

@ -0,0 +1,963 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based mostly on anv driver which is:
* Copyright © 2015 Intel 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 <X11/Xlib-xcb.h>
#include <X11/xshmfence.h>
#include <xcb/xcb.h>
#include <xcb/dri3.h>
#include <xcb/present.h>
#include <errno.h>
#include <unistd.h>
#include "radv_wsi.h"
#include "vk_format.h"
#include "util/hash_table.h"
struct wsi_x11_connection {
bool has_dri3;
bool has_present;
};
struct wsi_x11 {
struct radv_wsi_interface base;
pthread_mutex_t mutex;
/* Hash table of xcb_connection -> wsi_x11_connection mappings */
struct hash_table *connections;
};
static struct wsi_x11_connection *
wsi_x11_connection_create(struct radv_physical_device *device,
xcb_connection_t *conn)
{
xcb_query_extension_cookie_t dri3_cookie, pres_cookie;
xcb_query_extension_reply_t *dri3_reply, *pres_reply;
struct wsi_x11_connection *wsi_conn =
radv_alloc(&device->instance->alloc, sizeof(*wsi_conn), 8,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!wsi_conn)
return NULL;
dri3_cookie = xcb_query_extension(conn, 4, "DRI3");
pres_cookie = xcb_query_extension(conn, 7, "PRESENT");
dri3_reply = xcb_query_extension_reply(conn, dri3_cookie, NULL);
pres_reply = xcb_query_extension_reply(conn, pres_cookie, NULL);
if (dri3_reply == NULL || pres_reply == NULL) {
free(dri3_reply);
free(pres_reply);
radv_free(&device->instance->alloc, wsi_conn);
return NULL;
}
wsi_conn->has_dri3 = dri3_reply->present != 0;
wsi_conn->has_present = pres_reply->present != 0;
free(dri3_reply);
free(pres_reply);
return wsi_conn;
}
static void
wsi_x11_connection_destroy(struct radv_physical_device *device,
struct wsi_x11_connection *conn)
{
radv_free(&device->instance->alloc, conn);
}
static struct wsi_x11_connection *
wsi_x11_get_connection(struct radv_physical_device *device,
xcb_connection_t *conn)
{
struct wsi_x11 *wsi =
(struct wsi_x11 *)device->wsi[VK_ICD_WSI_PLATFORM_XCB];
pthread_mutex_lock(&wsi->mutex);
struct hash_entry *entry = _mesa_hash_table_search(wsi->connections, conn);
if (!entry) {
/* We're about to make a bunch of blocking calls. Let's drop the
* mutex for now so we don't block up too badly.
*/
pthread_mutex_unlock(&wsi->mutex);
struct wsi_x11_connection *wsi_conn =
wsi_x11_connection_create(device, conn);
pthread_mutex_lock(&wsi->mutex);
entry = _mesa_hash_table_search(wsi->connections, conn);
if (entry) {
/* Oops, someone raced us to it */
wsi_x11_connection_destroy(device, wsi_conn);
} else {
entry = _mesa_hash_table_insert(wsi->connections, conn, wsi_conn);
}
}
pthread_mutex_unlock(&wsi->mutex);
return entry->data;
}
static const VkSurfaceFormatKHR formats[] = {
{ .format = VK_FORMAT_B8G8R8A8_UNORM, },
{ .format = VK_FORMAT_B8G8R8A8_SRGB, },
};
static const VkPresentModeKHR present_modes[] = {
VK_PRESENT_MODE_MAILBOX_KHR,
};
static xcb_screen_t *
get_screen_for_root(xcb_connection_t *conn, xcb_window_t root)
{
xcb_screen_iterator_t screen_iter =
xcb_setup_roots_iterator(xcb_get_setup(conn));
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
if (screen_iter.data->root == root)
return screen_iter.data;
}
return NULL;
}
static xcb_visualtype_t *
screen_get_visualtype(xcb_screen_t *screen, xcb_visualid_t visual_id,
unsigned *depth)
{
xcb_depth_iterator_t depth_iter =
xcb_screen_allowed_depths_iterator(screen);
for (; depth_iter.rem; xcb_depth_next (&depth_iter)) {
xcb_visualtype_iterator_t visual_iter =
xcb_depth_visuals_iterator (depth_iter.data);
for (; visual_iter.rem; xcb_visualtype_next (&visual_iter)) {
if (visual_iter.data->visual_id == visual_id) {
if (depth)
*depth = depth_iter.data->depth;
return visual_iter.data;
}
}
}
return NULL;
}
static xcb_visualtype_t *
connection_get_visualtype(xcb_connection_t *conn, xcb_visualid_t visual_id,
unsigned *depth)
{
xcb_screen_iterator_t screen_iter =
xcb_setup_roots_iterator(xcb_get_setup(conn));
/* For this we have to iterate over all of the screens which is rather
* annoying. Fortunately, there is probably only 1.
*/
for (; screen_iter.rem; xcb_screen_next (&screen_iter)) {
xcb_visualtype_t *visual = screen_get_visualtype(screen_iter.data,
visual_id, depth);
if (visual)
return visual;
}
return NULL;
}
static xcb_visualtype_t *
get_visualtype_for_window(xcb_connection_t *conn, xcb_window_t window,
unsigned *depth)
{
xcb_query_tree_cookie_t tree_cookie;
xcb_get_window_attributes_cookie_t attrib_cookie;
xcb_query_tree_reply_t *tree;
xcb_get_window_attributes_reply_t *attrib;
tree_cookie = xcb_query_tree(conn, window);
attrib_cookie = xcb_get_window_attributes(conn, window);
tree = xcb_query_tree_reply(conn, tree_cookie, NULL);
attrib = xcb_get_window_attributes_reply(conn, attrib_cookie, NULL);
if (attrib == NULL || tree == NULL) {
free(attrib);
free(tree);
return NULL;
}
xcb_window_t root = tree->root;
xcb_visualid_t visual_id = attrib->visual;
free(attrib);
free(tree);
xcb_screen_t *screen = get_screen_for_root(conn, root);
if (screen == NULL)
return NULL;
return screen_get_visualtype(screen, visual_id, depth);
}
static bool
visual_has_alpha(xcb_visualtype_t *visual, unsigned depth)
{
uint32_t rgb_mask = visual->red_mask |
visual->green_mask |
visual->blue_mask;
uint32_t all_mask = 0xffffffff >> (32 - depth);
/* Do we have bits left over after RGB? */
return (all_mask & ~rgb_mask) != 0;
}
VkBool32 radv_GetPhysicalDeviceXcbPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
xcb_connection_t* connection,
xcb_visualid_t visual_id)
{
RADV_FROM_HANDLE(radv_physical_device, device, physicalDevice);
struct wsi_x11_connection *wsi_conn =
wsi_x11_get_connection(device, connection);
if (!wsi_conn->has_dri3) {
fprintf(stderr, "vulkan: No DRI3 support\n");
return false;
}
unsigned visual_depth;
if (!connection_get_visualtype(connection, visual_id, &visual_depth))
return false;
if (visual_depth != 24 && visual_depth != 32)
return false;
return true;
}
VkBool32 radv_GetPhysicalDeviceXlibPresentationSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
Display* dpy,
VisualID visualID)
{
return radv_GetPhysicalDeviceXcbPresentationSupportKHR(physicalDevice,
queueFamilyIndex,
XGetXCBConnection(dpy),
visualID);
}
static xcb_connection_t*
x11_surface_get_connection(VkIcdSurfaceBase *icd_surface)
{
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
return XGetXCBConnection(((VkIcdSurfaceXlib *)icd_surface)->dpy);
else
return ((VkIcdSurfaceXcb *)icd_surface)->connection;
}
static xcb_window_t
x11_surface_get_window(VkIcdSurfaceBase *icd_surface)
{
if (icd_surface->platform == VK_ICD_WSI_PLATFORM_XLIB)
return ((VkIcdSurfaceXlib *)icd_surface)->window;
else
return ((VkIcdSurfaceXcb *)icd_surface)->window;
}
static VkResult
x11_surface_get_support(VkIcdSurfaceBase *icd_surface,
struct radv_physical_device *device,
uint32_t queueFamilyIndex,
VkBool32* pSupported)
{
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
xcb_window_t window = x11_surface_get_window(icd_surface);
struct wsi_x11_connection *wsi_conn =
wsi_x11_get_connection(device, conn);
if (!wsi_conn)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
if (!wsi_conn->has_dri3) {
fprintf(stderr, "vulkan: No DRI3 support\n");
*pSupported = false;
return VK_SUCCESS;
}
unsigned visual_depth;
if (!get_visualtype_for_window(conn, window, &visual_depth)) {
*pSupported = false;
return VK_SUCCESS;
}
if (visual_depth != 24 && visual_depth != 32) {
*pSupported = false;
return VK_SUCCESS;
}
*pSupported = true;
return VK_SUCCESS;
}
static VkResult
x11_surface_get_capabilities(VkIcdSurfaceBase *icd_surface,
struct radv_physical_device *device,
VkSurfaceCapabilitiesKHR *caps)
{
xcb_connection_t *conn = x11_surface_get_connection(icd_surface);
xcb_window_t window = x11_surface_get_window(icd_surface);
xcb_get_geometry_cookie_t geom_cookie;
xcb_generic_error_t *err;
xcb_get_geometry_reply_t *geom;
unsigned visual_depth;
geom_cookie = xcb_get_geometry(conn, window);
/* This does a round-trip. This is why we do get_geometry first and
* wait to read the reply until after we have a visual.
*/
xcb_visualtype_t *visual =
get_visualtype_for_window(conn, window, &visual_depth);
geom = xcb_get_geometry_reply(conn, geom_cookie, &err);
if (geom) {
VkExtent2D extent = { geom->width, geom->height };
caps->currentExtent = extent;
caps->minImageExtent = extent;
caps->maxImageExtent = extent;
} else {
/* This can happen if the client didn't wait for the configure event
* to come back from the compositor. In that case, we don't know the
* size of the window so we just return valid "I don't know" stuff.
*/
caps->currentExtent = (VkExtent2D) { -1, -1 };
caps->minImageExtent = (VkExtent2D) { 1, 1 };
caps->maxImageExtent = (VkExtent2D) { INT16_MAX, INT16_MAX };
}
free(err);
free(geom);
if (visual_has_alpha(visual, visual_depth)) {
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
} else {
caps->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR |
VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
}
caps->minImageCount = 2;
caps->maxImageCount = 4;
caps->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
caps->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
caps->maxImageArrayLayers = 1;
caps->supportedUsageFlags =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
return VK_SUCCESS;
}
static VkResult
x11_surface_get_formats(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t *pSurfaceFormatCount,
VkSurfaceFormatKHR *pSurfaceFormats)
{
if (pSurfaceFormats == NULL) {
*pSurfaceFormatCount = ARRAY_SIZE(formats);
return VK_SUCCESS;
}
assert(*pSurfaceFormatCount >= ARRAY_SIZE(formats));
typed_memcpy(pSurfaceFormats, formats, *pSurfaceFormatCount);
*pSurfaceFormatCount = ARRAY_SIZE(formats);
return VK_SUCCESS;
}
static VkResult
x11_surface_get_present_modes(VkIcdSurfaceBase *surface,
struct radv_physical_device *device,
uint32_t *pPresentModeCount,
VkPresentModeKHR *pPresentModes)
{
if (pPresentModes == NULL) {
*pPresentModeCount = ARRAY_SIZE(present_modes);
return VK_SUCCESS;
}
assert(*pPresentModeCount >= ARRAY_SIZE(present_modes));
typed_memcpy(pPresentModes, present_modes, *pPresentModeCount);
*pPresentModeCount = ARRAY_SIZE(present_modes);
return VK_SUCCESS;
}
static VkResult
x11_surface_create_swapchain(VkIcdSurfaceBase *surface,
struct radv_device *device,
const VkSwapchainCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct radv_swapchain **swapchain);
VkResult radv_CreateXcbSurfaceKHR(
VkInstance _instance,
const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
RADV_FROM_HANDLE(radv_instance, instance, _instance);
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR);
VkIcdSurfaceXcb *surface;
surface = radv_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (surface == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
surface->base.platform = VK_ICD_WSI_PLATFORM_XCB;
surface->connection = pCreateInfo->connection;
surface->window = pCreateInfo->window;
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
return VK_SUCCESS;
}
VkResult radv_CreateXlibSurfaceKHR(
VkInstance _instance,
const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
RADV_FROM_HANDLE(radv_instance, instance, _instance);
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR);
VkIcdSurfaceXlib *surface;
surface = radv_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (surface == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
surface->base.platform = VK_ICD_WSI_PLATFORM_XLIB;
surface->dpy = pCreateInfo->dpy;
surface->window = pCreateInfo->window;
*pSurface = _VkIcdSurfaceBase_to_handle(&surface->base);
return VK_SUCCESS;
}
struct x11_image {
struct radv_image * image;
struct radv_device_memory * memory;
xcb_pixmap_t pixmap;
bool busy;
struct xshmfence * shm_fence;
uint32_t sync_fence;
};
struct x11_swapchain {
struct radv_swapchain base;
xcb_connection_t * conn;
xcb_window_t window;
xcb_gc_t gc;
VkExtent2D extent;
uint32_t image_count;
xcb_present_event_t event_id;
xcb_special_event_t * special_event;
uint64_t send_sbc;
uint32_t stamp;
struct x11_image images[0];
};
static VkResult
x11_get_images(struct radv_swapchain *radv_chain,
uint32_t* pCount, VkImage *pSwapchainImages)
{
struct x11_swapchain *chain = (struct x11_swapchain *)radv_chain;
if (pSwapchainImages == NULL) {
*pCount = chain->image_count;
return VK_SUCCESS;
}
assert(chain->image_count <= *pCount);
for (uint32_t i = 0; i < chain->image_count; i++)
pSwapchainImages[i] = radv_image_to_handle(chain->images[i].image);
*pCount = chain->image_count;
return VK_SUCCESS;
}
static VkResult
x11_handle_dri3_present_event(struct x11_swapchain *chain,
xcb_present_generic_event_t *event)
{
switch (event->evtype) {
case XCB_PRESENT_CONFIGURE_NOTIFY: {
xcb_present_configure_notify_event_t *config = (void *) event;
if (config->width != chain->extent.width ||
config->height != chain->extent.height)
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
break;
}
case XCB_PRESENT_EVENT_IDLE_NOTIFY: {
xcb_present_idle_notify_event_t *idle = (void *) event;
for (unsigned i = 0; i < chain->image_count; i++) {
if (chain->images[i].pixmap == idle->pixmap) {
chain->images[i].busy = false;
break;
}
}
break;
}
case XCB_PRESENT_COMPLETE_NOTIFY:
default:
break;
}
return VK_SUCCESS;
}
static VkResult
x11_acquire_next_image(struct radv_swapchain *radv_chain,
uint64_t timeout,
VkSemaphore semaphore,
uint32_t *image_index)
{
struct x11_swapchain *chain = (struct x11_swapchain *)radv_chain;
while (1) {
for (uint32_t i = 0; i < chain->image_count; i++) {
if (!chain->images[i].busy) {
/* We found a non-busy image */
xshmfence_await(chain->images[i].shm_fence);
*image_index = i;
return VK_SUCCESS;
}
}
xcb_flush(chain->conn);
xcb_generic_event_t *event =
xcb_wait_for_special_event(chain->conn, chain->special_event);
if (!event)
return vk_error(VK_ERROR_OUT_OF_DATE_KHR);
VkResult result = x11_handle_dri3_present_event(chain, (void *)event);
free(event);
if (result != VK_SUCCESS)
return result;
}
}
static VkResult
x11_queue_present(struct radv_swapchain *radv_chain,
struct radv_queue *queue,
uint32_t image_index)
{
struct x11_swapchain *chain = (struct x11_swapchain *)radv_chain;
struct x11_image *image = &chain->images[image_index];
assert(image_index < chain->image_count);
uint32_t options = XCB_PRESENT_OPTION_NONE;
int64_t target_msc = 0;
int64_t divisor = 0;
int64_t remainder = 0;
options |= XCB_PRESENT_OPTION_ASYNC;
xshmfence_reset(image->shm_fence);
++chain->send_sbc;
xcb_void_cookie_t cookie =
xcb_present_pixmap(chain->conn,
chain->window,
image->pixmap,
(uint32_t) chain->send_sbc,
0, /* valid */
0, /* update */
0, /* x_off */
0, /* y_off */
XCB_NONE, /* target_crtc */
XCB_NONE,
image->sync_fence,
options,
target_msc,
divisor,
remainder, 0, NULL);
xcb_discard_reply(chain->conn, cookie.sequence);
image->busy = true;
xcb_flush(chain->conn);
return VK_SUCCESS;
}
static VkResult
x11_image_init(struct radv_device *device, struct x11_swapchain *chain,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct x11_image *image)
{
xcb_void_cookie_t cookie;
VkResult result = VK_SUCCESS;
int fd;
VkImage image_h;
bool bret;
struct radeon_surf *surface;
result = radv_image_create(radv_device_to_handle(device),
&(struct radv_image_create_info) {
.vk_info =
&(VkImageCreateInfo) {
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
.imageType = VK_IMAGE_TYPE_2D,
.format = pCreateInfo->imageFormat,
.extent = {
.width = pCreateInfo->imageExtent.width,
.height = pCreateInfo->imageExtent.height,
.depth = 1
},
.mipLevels = 1,
.arrayLayers = 1,
.samples = 1,
/* FIXME: Need a way to use X tiling to allow scanout */
.tiling = VK_IMAGE_TILING_OPTIMAL,
.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.flags = 0,
},
.scanout = true},
NULL,
&image_h);
if (result != VK_SUCCESS)
return result;
image->image = radv_image_from_handle(image_h);
VkDeviceMemory memory_h;
result = radv_AllocateMemory(radv_device_to_handle(device),
&(VkMemoryAllocateInfo) {
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
.allocationSize = image->image->size,
.memoryTypeIndex = 0,
},
NULL /* XXX: pAllocator */,
&memory_h);
if (result != VK_SUCCESS)
goto fail_create_image;
image->memory = radv_device_memory_from_handle(memory_h);
// image->memory->bo.is_winsys_bo = true;
radv_BindImageMemory(VK_NULL_HANDLE, image_h, memory_h, 0);
bret = device->ws->buffer_get_fd(device->ws,
image->memory->bo, &fd);
if (bret == false)
goto fail_alloc_memory;
{
struct radeon_bo_metadata metadata;
radv_init_metadata(device, image->image, &metadata);
device->ws->buffer_set_metadata(image->memory->bo, &metadata);
}
surface = &image->image->surface;
uint32_t bpp = 32;
uint32_t depth = 24;
image->pixmap = xcb_generate_id(chain->conn);
cookie =
xcb_dri3_pixmap_from_buffer_checked(chain->conn,
image->pixmap,
chain->window,
image->image->size,
pCreateInfo->imageExtent.width,
pCreateInfo->imageExtent.height,
surface->level[0].pitch_bytes,
depth, bpp, fd);
xcb_discard_reply(chain->conn, cookie.sequence);
int fence_fd = xshmfence_alloc_shm();
if (fence_fd < 0)
goto fail_pixmap;
image->shm_fence = xshmfence_map_shm(fence_fd);
if (image->shm_fence == NULL)
goto fail_shmfence_alloc;
image->sync_fence = xcb_generate_id(chain->conn);
xcb_dri3_fence_from_fd(chain->conn,
image->pixmap,
image->sync_fence,
false,
fence_fd);
image->busy = false;
xshmfence_trigger(image->shm_fence);
return VK_SUCCESS;
fail_shmfence_alloc:
close(fence_fd);
fail_pixmap:
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
fail_alloc_memory:
radv_FreeMemory(radv_device_to_handle(chain->base.device),
radv_device_memory_to_handle(image->memory), pAllocator);
fail_create_image:
radv_DestroyImage(radv_device_to_handle(chain->base.device),
radv_image_to_handle(image->image), pAllocator);
return result;
}
static void
x11_image_finish(struct x11_swapchain *chain,
const VkAllocationCallbacks* pAllocator,
struct x11_image *image)
{
xcb_void_cookie_t cookie;
cookie = xcb_sync_destroy_fence(chain->conn, image->sync_fence);
xcb_discard_reply(chain->conn, cookie.sequence);
xshmfence_unmap_shm(image->shm_fence);
cookie = xcb_free_pixmap(chain->conn, image->pixmap);
xcb_discard_reply(chain->conn, cookie.sequence);
radv_DestroyImage(radv_device_to_handle(chain->base.device),
radv_image_to_handle(image->image), pAllocator);
radv_FreeMemory(radv_device_to_handle(chain->base.device),
radv_device_memory_to_handle(image->memory), pAllocator);
}
static VkResult
x11_swapchain_destroy(struct radv_swapchain *radv_chain,
const VkAllocationCallbacks *pAllocator)
{
struct x11_swapchain *chain = (struct x11_swapchain *)radv_chain;
for (uint32_t i = 0; i < chain->image_count; i++)
x11_image_finish(chain, pAllocator, &chain->images[i]);
xcb_unregister_for_special_event(chain->conn, chain->special_event);
radv_free2(&chain->base.device->alloc, pAllocator, chain);
return VK_SUCCESS;
}
static VkResult
x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface,
struct radv_device *device,
const VkSwapchainCreateInfoKHR *pCreateInfo,
const VkAllocationCallbacks* pAllocator,
struct radv_swapchain **swapchain_out)
{
struct x11_swapchain *chain;
xcb_void_cookie_t cookie;
VkResult result;
assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR);
int num_images = pCreateInfo->minImageCount;
/* For true mailbox mode, we need at least 4 images:
* 1) One to scan out from
* 2) One to have queued for scan-out
* 3) One to be currently held by the Wayland compositor
* 4) One to render to
*/
if (pCreateInfo->presentMode == VK_PRESENT_MODE_MAILBOX_KHR)
num_images = MAX(num_images, 4);
size_t size = sizeof(*chain) + num_images * sizeof(chain->images[0]);
chain = radv_alloc2(&device->alloc, pAllocator, size, 8,
VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);
if (chain == NULL)
return vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
chain->base.device = device;
chain->base.destroy = x11_swapchain_destroy;
chain->base.get_images = x11_get_images;
chain->base.acquire_next_image = x11_acquire_next_image;
chain->base.queue_present = x11_queue_present;
chain->conn = x11_surface_get_connection(icd_surface);
chain->window = x11_surface_get_window(icd_surface);
chain->extent = pCreateInfo->imageExtent;
chain->image_count = num_images;
chain->send_sbc = 0;
chain->event_id = xcb_generate_id(chain->conn);
xcb_present_select_input(chain->conn, chain->event_id, chain->window,
XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY |
XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY |
XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY);
/* Create an XCB event queue to hold present events outside of the usual
* application event queue
*/
chain->special_event =
xcb_register_for_special_xge(chain->conn, &xcb_present_id,
chain->event_id, NULL);
chain->gc = xcb_generate_id(chain->conn);
if (!chain->gc) {
/* FINISHME: Choose a better error. */
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_register;
}
cookie = xcb_create_gc(chain->conn,
chain->gc,
chain->window,
XCB_GC_GRAPHICS_EXPOSURES,
(uint32_t []) { 0 });
xcb_discard_reply(chain->conn, cookie.sequence);
uint32_t image = 0;
for (; image < chain->image_count; image++) {
result = x11_image_init(device, chain, pCreateInfo, pAllocator,
&chain->images[image]);
if (result != VK_SUCCESS)
goto fail_init_images;
}
*swapchain_out = &chain->base;
return VK_SUCCESS;
fail_init_images:
for (uint32_t j = 0; j < image; j++)
x11_image_finish(chain, pAllocator, &chain->images[j]);
fail_register:
xcb_unregister_for_special_event(chain->conn, chain->special_event);
radv_free2(&device->alloc, pAllocator, chain);
return result;
}
VkResult
radv_x11_init_wsi(struct radv_physical_device *device)
{
struct wsi_x11 *wsi;
VkResult result;
wsi = radv_alloc(&device->instance->alloc, sizeof(*wsi), 8,
VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE);
if (!wsi) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail;
}
int ret = pthread_mutex_init(&wsi->mutex, NULL);
if (ret != 0) {
if (ret == ENOMEM) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
} else {
/* FINISHME: Choose a better error. */
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
}
goto fail_alloc;
}
wsi->connections = _mesa_hash_table_create(NULL, _mesa_hash_pointer,
_mesa_key_pointer_equal);
if (!wsi->connections) {
result = vk_error(VK_ERROR_OUT_OF_HOST_MEMORY);
goto fail_mutex;
}
wsi->base.get_support = x11_surface_get_support;
wsi->base.get_capabilities = x11_surface_get_capabilities;
wsi->base.get_formats = x11_surface_get_formats;
wsi->base.get_present_modes = x11_surface_get_present_modes;
wsi->base.create_swapchain = x11_surface_create_swapchain;
device->wsi[VK_ICD_WSI_PLATFORM_XCB] = &wsi->base;
device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = &wsi->base;
return VK_SUCCESS;
fail_mutex:
pthread_mutex_destroy(&wsi->mutex);
fail_alloc:
radv_free(&device->instance->alloc, wsi);
fail:
device->wsi[VK_ICD_WSI_PLATFORM_XCB] = NULL;
device->wsi[VK_ICD_WSI_PLATFORM_XLIB] = NULL;
return result;
}
void
radv_x11_finish_wsi(struct radv_physical_device *device)
{
struct wsi_x11 *wsi =
(struct wsi_x11 *)device->wsi[VK_ICD_WSI_PLATFORM_XCB];
if (wsi) {
_mesa_hash_table_destroy(wsi->connections, NULL);
pthread_mutex_destroy(&wsi->mutex);
radv_free(&device->instance->alloc, wsi);
}
}

File diff suppressed because it is too large Load Diff

449
src/amd/vulkan/vk_format.h Normal file
View File

@ -0,0 +1,449 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* Based on u_format.h which is:
* Copyright 2009-2010 Vmware, Inc.
* 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.
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <assert.h>
#include <vulkan/vulkan.h>
enum vk_format_layout {
/**
* Formats with vk_format_block::width == vk_format_block::height == 1
* that can be described as an ordinary data structure.
*/
VK_FORMAT_LAYOUT_PLAIN = 0,
/**
* Formats with sub-sampled channels.
*
* This is for formats like YVYU where there is less than one sample per
* pixel.
*/
VK_FORMAT_LAYOUT_SUBSAMPLED = 3,
/**
* S3 Texture Compression formats.
*/
VK_FORMAT_LAYOUT_S3TC = 4,
/**
* Red-Green Texture Compression formats.
*/
VK_FORMAT_LAYOUT_RGTC = 5,
/**
* Ericsson Texture Compression
*/
VK_FORMAT_LAYOUT_ETC = 6,
/**
* BC6/7 Texture Compression
*/
VK_FORMAT_LAYOUT_BPTC = 7,
/**
* ASTC
*/
VK_FORMAT_LAYOUT_ASTC = 8,
/**
* Everything else that doesn't fit in any of the above layouts.
*/
VK_FORMAT_LAYOUT_OTHER = 9
};
struct vk_format_block
{
/** Block width in pixels */
unsigned width;
/** Block height in pixels */
unsigned height;
/** Block size in bits */
unsigned bits;
};
enum vk_format_type {
VK_FORMAT_TYPE_VOID = 0,
VK_FORMAT_TYPE_UNSIGNED = 1,
VK_FORMAT_TYPE_SIGNED = 2,
VK_FORMAT_TYPE_FIXED = 3,
VK_FORMAT_TYPE_FLOAT = 4
};
enum vk_format_colorspace {
VK_FORMAT_COLORSPACE_RGB = 0,
VK_FORMAT_COLORSPACE_SRGB = 1,
VK_FORMAT_COLORSPACE_YUV = 2,
VK_FORMAT_COLORSPACE_ZS = 3
};
struct vk_format_channel_description {
unsigned type:5;
unsigned normalized:1;
unsigned pure_integer:1;
unsigned scaled:1;
unsigned size:8;
unsigned shift:16;
};
struct vk_format_description
{
VkFormat format;
const char *name;
const char *short_name;
struct vk_format_block block;
enum vk_format_layout layout;
unsigned nr_channels:3;
unsigned is_array:1;
unsigned is_bitmask:1;
unsigned is_mixed:1;
struct vk_format_channel_description channel[4];
unsigned char swizzle[4];
enum vk_format_colorspace colorspace;
};
extern const struct vk_format_description vk_format_description_table[];
const struct vk_format_description *vk_format_description(VkFormat format);
/**
* Return total bits needed for the pixel format per block.
*/
static inline uint
vk_format_get_blocksizebits(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return 0;
}
return desc->block.bits;
}
/**
* Return bytes per block (not pixel) for the given format.
*/
static inline uint
vk_format_get_blocksize(VkFormat format)
{
uint bits = vk_format_get_blocksizebits(format);
uint bytes = bits / 8;
assert(bits % 8 == 0);
assert(bytes > 0);
if (bytes == 0) {
bytes = 1;
}
return bytes;
}
static inline uint
vk_format_get_blockwidth(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return 1;
}
return desc->block.width;
}
static inline uint
vk_format_get_blockheight(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return 1;
}
return desc->block.height;
}
/**
* Return the index of the first non-void channel
* -1 if no non-void channels
*/
static inline int
vk_format_get_first_non_void_channel(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
int i;
for (i = 0; i < 4; i++)
if (desc->channel[i].type != VK_FORMAT_TYPE_VOID)
break;
if (i == 4)
return -1;
return i;
}
enum vk_swizzle {
VK_SWIZZLE_X,
VK_SWIZZLE_Y,
VK_SWIZZLE_Z,
VK_SWIZZLE_W,
VK_SWIZZLE_0,
VK_SWIZZLE_1,
VK_SWIZZLE_NONE,
VK_SWIZZLE_MAX, /**< Number of enums counter (must be last) */
};
static inline VkImageAspectFlags
vk_format_aspects(VkFormat format)
{
switch (format) {
case VK_FORMAT_UNDEFINED:
return 0;
case VK_FORMAT_S8_UINT:
return VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_FORMAT_D16_UNORM_S8_UINT:
case VK_FORMAT_D24_UNORM_S8_UINT:
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
case VK_FORMAT_D16_UNORM:
case VK_FORMAT_X8_D24_UNORM_PACK32:
case VK_FORMAT_D32_SFLOAT:
return VK_IMAGE_ASPECT_DEPTH_BIT;
default:
return VK_IMAGE_ASPECT_COLOR_BIT;
}
}
static inline enum vk_swizzle
radv_swizzle_conv(int idx, const unsigned char chan[4], VkComponentSwizzle vk_swiz)
{
int x;
switch (vk_swiz) {
case VK_COMPONENT_SWIZZLE_IDENTITY:
return chan[idx];
case VK_COMPONENT_SWIZZLE_ZERO:
return VK_SWIZZLE_0;
case VK_COMPONENT_SWIZZLE_ONE:
return VK_SWIZZLE_1;
case VK_COMPONENT_SWIZZLE_R:
for (x = 0; x < 4; x++)
if (chan[x] == 0)
return x;
return VK_SWIZZLE_0;
case VK_COMPONENT_SWIZZLE_G:
for (x = 0; x < 4; x++)
if (chan[x] == 1)
return x;
return VK_SWIZZLE_0;
case VK_COMPONENT_SWIZZLE_B:
for (x = 0; x < 4; x++)
if (chan[x] == 2)
return x;
return VK_SWIZZLE_0;
case VK_COMPONENT_SWIZZLE_A:
for (x = 0; x < 4; x++)
if (chan[x] == 3)
return x;
return VK_SWIZZLE_1;
default:
return chan[idx];
}
}
static inline void vk_format_compose_swizzles(const VkComponentMapping *mapping,
const unsigned char swz[4],
enum vk_swizzle dst[4])
{
dst[0] = radv_swizzle_conv(0, swz, mapping->r);
dst[1] = radv_swizzle_conv(1, swz, mapping->g);
dst[2] = radv_swizzle_conv(2, swz, mapping->b);
dst[3] = radv_swizzle_conv(3, swz, mapping->a);
}
static inline bool
vk_format_is_compressed(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return false;
}
switch (desc->layout) {
case VK_FORMAT_LAYOUT_S3TC:
case VK_FORMAT_LAYOUT_RGTC:
case VK_FORMAT_LAYOUT_ETC:
case VK_FORMAT_LAYOUT_BPTC:
case VK_FORMAT_LAYOUT_ASTC:
/* XXX add other formats in the future */
return true;
default:
return false;
}
}
static inline bool
vk_format_has_depth(const struct vk_format_description *desc)
{
return desc->colorspace == VK_FORMAT_COLORSPACE_ZS &&
desc->swizzle[0] != VK_SWIZZLE_NONE;
}
static inline bool
vk_format_has_stencil(const struct vk_format_description *desc)
{
return desc->colorspace == VK_FORMAT_COLORSPACE_ZS &&
desc->swizzle[1] != VK_SWIZZLE_NONE;
}
static inline bool
vk_format_is_depth_or_stencil(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return false;
}
return vk_format_has_depth(desc) ||
vk_format_has_stencil(desc);
}
static inline bool
vk_format_is_depth(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
assert(desc);
if (!desc) {
return false;
}
return vk_format_has_depth(desc);
}
static inline bool
vk_format_is_color(VkFormat format)
{
return !vk_format_is_depth_or_stencil(format);
}
static inline VkFormat
vk_format_depth_only(VkFormat format)
{
switch (format) {
case VK_FORMAT_D16_UNORM_S8_UINT:
return VK_FORMAT_D16_UNORM;
case VK_FORMAT_D24_UNORM_S8_UINT:
return VK_FORMAT_X8_D24_UNORM_PACK32;
case VK_FORMAT_D32_SFLOAT_S8_UINT:
return VK_FORMAT_D32_SFLOAT;
default:
return format;
}
}
static inline bool
vk_format_is_int(VkFormat format)
{
const struct vk_format_description *desc = vk_format_description(format);
int channel = vk_format_get_first_non_void_channel(format);
return channel >= 0 && desc->channel[channel].pure_integer;
}
static inline VkFormat
vk_format_stencil_only(VkFormat format)
{
return VK_FORMAT_S8_UINT;
}
static inline uint
vk_format_get_component_bits(VkFormat format,
enum vk_format_colorspace colorspace,
uint component)
{
const struct vk_format_description *desc = vk_format_description(format);
enum vk_format_colorspace desc_colorspace;
assert(format);
if (!format) {
return 0;
}
assert(component < 4);
/* Treat RGB and SRGB as equivalent. */
if (colorspace == VK_FORMAT_COLORSPACE_SRGB) {
colorspace = VK_FORMAT_COLORSPACE_RGB;
}
if (desc->colorspace == VK_FORMAT_COLORSPACE_SRGB) {
desc_colorspace = VK_FORMAT_COLORSPACE_RGB;
} else {
desc_colorspace = desc->colorspace;
}
if (desc_colorspace != colorspace) {
return 0;
}
switch (desc->swizzle[component]) {
case VK_SWIZZLE_X:
return desc->channel[0].size;
case VK_SWIZZLE_Y:
return desc->channel[1].size;
case VK_SWIZZLE_Z:
return desc->channel[2].size;
case VK_SWIZZLE_W:
return desc->channel[3].size;
default:
return 0;
}
}
#ifdef __cplusplus
} // extern "C" {
#endif

View File

@ -0,0 +1,188 @@
/* this is pretty much taken from the gallium one. */
VK_FORMAT_UNDEFINED , plain, 1, 1, u8 , , , , x001, rgb
VK_FORMAT_R4G4_UNORM_PACK8 , plain, 1, 1, un4 , un4 , , , xy01, rgb
VK_FORMAT_R4G4B4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wzyx, rgb
VK_FORMAT_B4G4R4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wxyz, rgb
VK_FORMAT_R5G6B5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , zyx1, rgb
VK_FORMAT_B5G6R5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , xyz1, rgb
VK_FORMAT_R5G5B5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wzyx, rgb
VK_FORMAT_B5G5R5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wxyz, rgb
VK_FORMAT_A1R5G5B5_UNORM_PACK16 , plain, 1, 1, un5 , un5 , un5 , un1 , zyxw, rgb
VK_FORMAT_R8_UNORM , plain, 1, 1, un8 , , , , x001, rgb
VK_FORMAT_R8_SNORM , plain, 1, 1, sn8 , , , , x001, rgb
VK_FORMAT_R8_USCALED , plain, 1, 1, us8 , , , , x001, rgb
VK_FORMAT_R8_SSCALED , plain, 1, 1, ss8 , , , , x001, rgb
VK_FORMAT_R8_UINT , plain, 1, 1, up8 , , , , x001, rgb
VK_FORMAT_R8_SINT , plain, 1, 1, sp8 , , , , x001, rgb
VK_FORMAT_R8_SRGB , plain, 1, 1, un8 , , , , x001, srgb
VK_FORMAT_R8G8_UNORM , plain, 1, 1, un8 , un8 , , , xy01, rgb
VK_FORMAT_R8G8_SNORM , plain, 1, 1, sn8 , sn8 , , , xy01, rgb
VK_FORMAT_R8G8_USCALED , plain, 1, 1, us8 , us8 , , , xy01, rgb
VK_FORMAT_R8G8_SSCALED , plain, 1, 1, ss8 , ss8 , , , xy01, rgb
VK_FORMAT_R8G8_UINT , plain, 1, 1, up8 , up8 , , , xy01, rgb
VK_FORMAT_R8G8_SINT , plain, 1, 1, sp8 , sp8 , , , xy01, rgb
VK_FORMAT_R8G8_SRGB , plain, 1, 1, un8 , un8 , , , xy01, srgb
VK_FORMAT_R8G8B8_UNORM , plain, 1, 1, un8 , un8 , un8 , , xyz1, rgb
VK_FORMAT_R8G8B8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , xyz1, rgb
VK_FORMAT_R8G8B8_USCALED , plain, 1, 1, us8 , us8 , us8 , , xyz1, rgb
VK_FORMAT_R8G8B8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , xyz1, rgb
VK_FORMAT_R8G8B8_UINT , plain, 1, 1, up8 , up8 , up8 , , xyz1, rgb
VK_FORMAT_R8G8B8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , xyz1, rgb
VK_FORMAT_R8G8B8_SRGB , plain, 1, 1, un8 , un8 , un8 , , xyz1, srgb
VK_FORMAT_B8G8R8_UNORM , plain, 1, 1, un8 , un8 , un8 , , zyx1, rgb
VK_FORMAT_B8G8R8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , zyx1, rgb
VK_FORMAT_B8G8R8_USCALED , plain, 1, 1, us8 , us8 , us8 , , zyx1, rgb
VK_FORMAT_B8G8R8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , zyx1, rgb
VK_FORMAT_B8G8R8_UINT , plain, 1, 1, up8 , up8 , up8 , , zyx1, rgb
VK_FORMAT_B8G8R8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , zyx1, rgb
VK_FORMAT_B8G8R8_SRGB , plain, 1, 1, un8 , un8 , un8 , , zyx1, srgb
VK_FORMAT_R8G8B8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb
VK_FORMAT_R8G8B8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb
VK_FORMAT_B8G8R8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , zyxw, rgb
VK_FORMAT_B8G8R8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, srgb
VK_FORMAT_A8B8G8R8_UNORM_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_SNORM_PACK32 , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_USCALED_PACK32 , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_SSCALED_PACK32 , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_UINT_PACK32 , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_SINT_PACK32 , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb
VK_FORMAT_A8B8G8R8_SRGB_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb
VK_FORMAT_A2R10G10B10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , zyxw, rgb
VK_FORMAT_A2R10G10B10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , zyxw, rgb
VK_FORMAT_A2R10G10B10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , zyxw, rgb
VK_FORMAT_A2R10G10B10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , zyxw, rgb
VK_FORMAT_A2R10G10B10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , zyxw, rgb
VK_FORMAT_A2R10G10B10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , zyxw, rgb
VK_FORMAT_A2B10G10R10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , xyzw, rgb
VK_FORMAT_A2B10G10R10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , xyzw, rgb
VK_FORMAT_A2B10G10R10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , xyzw, rgb
VK_FORMAT_A2B10G10R10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , xyzw, rgb
VK_FORMAT_A2B10G10R10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , xyzw, rgb
VK_FORMAT_A2B10G10R10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , xyzw, rgb
VK_FORMAT_R16_UNORM , plain, 1, 1, un16, , , , x001, rgb
VK_FORMAT_R16_SNORM , plain, 1, 1, sn16, , , , x001, rgb
VK_FORMAT_R16_USCALED , plain, 1, 1, us16, , , , x001, rgb
VK_FORMAT_R16_SSCALED , plain, 1, 1, ss16, , , , x001, rgb
VK_FORMAT_R16_UINT , plain, 1, 1, up16, , , , x001, rgb
VK_FORMAT_R16_SINT , plain, 1, 1, sp16, , , , x001, rgb
VK_FORMAT_R16_SFLOAT , plain, 1, 1, f16 , , , , x001, rgb
VK_FORMAT_R16G16_UNORM , plain, 1, 1, un16, un16, , , xy01, rgb
VK_FORMAT_R16G16_SNORM , plain, 1, 1, sn16, sn16, , , xy01, rgb
VK_FORMAT_R16G16_USCALED , plain, 1, 1, us16, us16, , , xy01, rgb
VK_FORMAT_R16G16_SSCALED , plain, 1, 1, ss16, ss16, , , xy01, rgb
VK_FORMAT_R16G16_UINT , plain, 1, 1, up16, up16, , , xy01, rgb
VK_FORMAT_R16G16_SINT , plain, 1, 1, sp16, sp16, , , xy01, rgb
VK_FORMAT_R16G16_SFLOAT , plain, 1, 1, f16 , f16 , , , xy01, rgb
VK_FORMAT_R16G16B16_UNORM , plain, 1, 1, un16, un16, un16, , xyz1, rgb
VK_FORMAT_R16G16B16_SNORM , plain, 1, 1, sn16, sn16, sn16, , xyz1, rgb
VK_FORMAT_R16G16B16_USCALED , plain, 1, 1, us16, us16, us16, , xyz1, rgb
VK_FORMAT_R16G16B16_SSCALED , plain, 1, 1, ss16, ss16, ss16, , xyz1, rgb
VK_FORMAT_R16G16B16_UINT , plain, 1, 1, up16, up16, up16, , xyz1, rgb
VK_FORMAT_R16G16B16_SINT , plain, 1, 1, sp16, sp16, sp16, , xyz1, rgb
VK_FORMAT_R16G16B16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , , xyz1, rgb
VK_FORMAT_R16G16B16A16_UNORM , plain, 1, 1, un16, un16, un16, un16, xyzw, rgb
VK_FORMAT_R16G16B16A16_SNORM , plain, 1, 1, sn16, sn16, sn16, sn16, xyzw, rgb
VK_FORMAT_R16G16B16A16_USCALED , plain, 1, 1, us16, us16, us16, us16, xyzw, rgb
VK_FORMAT_R16G16B16A16_SSCALED , plain, 1, 1, ss16, ss16, ss16, ss16, xyzw, rgb
VK_FORMAT_R16G16B16A16_UINT , plain, 1, 1, up16, up16, up16, up16, xyzw, rgb
VK_FORMAT_R16G16B16A16_SINT , plain, 1, 1, sp16, sp16, sp16, sp16, xyzw, rgb
VK_FORMAT_R16G16B16A16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , f16 , xyzw, rgb
VK_FORMAT_R32_UINT , plain, 1, 1, up32, , , , x001, rgb
VK_FORMAT_R32_SINT , plain, 1, 1, sp32, , , , x001, rgb
VK_FORMAT_R32_SFLOAT , plain, 1, 1, f32 , , , , x001, rgb
VK_FORMAT_R32G32_UINT , plain, 1, 1, up32, up32, , , xy01, rgb
VK_FORMAT_R32G32_SINT , plain, 1, 1, sp32, sp32, , , xy01, rgb
VK_FORMAT_R32G32_SFLOAT , plain, 1, 1, f32 , f32 , , , xy01, rgb
VK_FORMAT_R32G32B32_UINT , plain, 1, 1, up32, up32, up32, , xyz1, rgb
VK_FORMAT_R32G32B32_SINT , plain, 1, 1, sp32, sp32, sp32, , xyz1, rgb
VK_FORMAT_R32G32B32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , , xyz1, rgb
VK_FORMAT_R32G32B32A32_UINT , plain, 1, 1, up32, up32, up32, up32, xyzw, rgb
VK_FORMAT_R32G32B32A32_SINT , plain, 1, 1, sp32, sp32, sp32, sp32, xyzw, rgb
VK_FORMAT_R32G32B32A32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , f32 , xyzw, rgb
VK_FORMAT_R64_UINT , plain, 1, 1, up64, , , , x001, rgb
VK_FORMAT_R64_SINT , plain, 1, 1, sp64, , , , x001, rgb
VK_FORMAT_R64_SFLOAT , plain, 1, 1, f64 , , , , x001, rgb
VK_FORMAT_R64G64_UINT , plain, 1, 1, up64, up64, , , xy01, rgb
VK_FORMAT_R64G64_SINT , plain, 1, 1, sp64, sp64, , , xy01, rgb
VK_FORMAT_R64G64_SFLOAT , plain, 1, 1, f64 , f64 , , , xy01, rgb
VK_FORMAT_R64G64B64_UINT , plain, 1, 1, up64, up64, up64, , xyz1, rgb
VK_FORMAT_R64G64B64_SINT , plain, 1, 1, sp64, sp64, sp64, , xyz1, rgb
VK_FORMAT_R64G64B64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , , xyz1, rgb
VK_FORMAT_R64G64B64A64_UINT , plain, 1, 1, up64, up64, up64, up64, xyzw, rgb
VK_FORMAT_R64G64B64A64_SINT , plain, 1, 1, sp64, sp64, sp64, sp64, xyzw, rgb
VK_FORMAT_R64G64B64A64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , f64 , xyzw, rgb
VK_FORMAT_B10G11R11_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb
VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb
VK_FORMAT_D16_UNORM , plain, 1, 1, un16, , , , x___, zs
VK_FORMAT_X8_D24_UNORM_PACK32 , plain, 1, 1, un24, x8 , , , x___, zs
VK_FORMAT_D32_SFLOAT , plain, 1, 1, f32 , , , , x___, zs
VK_FORMAT_S8_UINT , plain, 1, 1, up8 , , , , _x__, zs
VK_FORMAT_D16_UNORM_S8_UINT , plain, 1, 1, un16, up8 , , , xy__, zs
VK_FORMAT_D24_UNORM_S8_UINT , plain, 1, 1, un24, up8 , , , xy__, zs
VK_FORMAT_D32_SFLOAT_S8_UINT , plain, 1, 1, f32 , up8 , , , xy__, zs
VK_FORMAT_BC1_RGB_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, rgb
VK_FORMAT_BC1_RGB_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, srgb
VK_FORMAT_BC1_RGBA_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, rgb
VK_FORMAT_BC1_RGBA_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, srgb
VK_FORMAT_BC2_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb
VK_FORMAT_BC2_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb
VK_FORMAT_BC3_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb
VK_FORMAT_BC3_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb
VK_FORMAT_BC4_UNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb
VK_FORMAT_BC4_SNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb
VK_FORMAT_BC5_UNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb
VK_FORMAT_BC5_SNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb
VK_FORMAT_BC6H_UFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb
VK_FORMAT_BC6H_SFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb
VK_FORMAT_BC7_UNORM_BLOCK , bptc, 4, 4, x128, , , , xyzw, rgb
VK_FORMAT_BC7_SRGB_BLOCK , bptc, 4, 4, x128, , , , xyzw, srgb
VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
VK_FORMAT_EAC_R11_UNORM_BLOCK,
VK_FORMAT_EAC_R11_SNORM_BLOCK,
VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
VK_FORMAT_ASTC_12x12_SRGB_BLOCK,
1 /* this is pretty much taken from the gallium one. */
2 VK_FORMAT_UNDEFINED , plain, 1, 1, u8 , , , , x001, rgb
3 VK_FORMAT_R4G4_UNORM_PACK8 , plain, 1, 1, un4 , un4 , , , xy01, rgb
4 VK_FORMAT_R4G4B4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wzyx, rgb
5 VK_FORMAT_B4G4R4A4_UNORM_PACK16 , plain, 1, 1, un4 , un4 , un4 , un4 , wxyz, rgb
6 VK_FORMAT_R5G6B5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , zyx1, rgb
7 VK_FORMAT_B5G6R5_UNORM_PACK16 , plain, 1, 1, un5 , un6 , un5 , , xyz1, rgb
8 VK_FORMAT_R5G5B5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wzyx, rgb
9 VK_FORMAT_B5G5R5A1_UNORM_PACK16 , plain, 1, 1, un1 , un5 , un5 , un5 , wxyz, rgb
10 VK_FORMAT_A1R5G5B5_UNORM_PACK16 , plain, 1, 1, un5 , un5 , un5 , un1 , zyxw, rgb
11 VK_FORMAT_R8_UNORM , plain, 1, 1, un8 , , , , x001, rgb
12 VK_FORMAT_R8_SNORM , plain, 1, 1, sn8 , , , , x001, rgb
13 VK_FORMAT_R8_USCALED , plain, 1, 1, us8 , , , , x001, rgb
14 VK_FORMAT_R8_SSCALED , plain, 1, 1, ss8 , , , , x001, rgb
15 VK_FORMAT_R8_UINT , plain, 1, 1, up8 , , , , x001, rgb
16 VK_FORMAT_R8_SINT , plain, 1, 1, sp8 , , , , x001, rgb
17 VK_FORMAT_R8_SRGB , plain, 1, 1, un8 , , , , x001, srgb
18 VK_FORMAT_R8G8_UNORM , plain, 1, 1, un8 , un8 , , , xy01, rgb
19 VK_FORMAT_R8G8_SNORM , plain, 1, 1, sn8 , sn8 , , , xy01, rgb
20 VK_FORMAT_R8G8_USCALED , plain, 1, 1, us8 , us8 , , , xy01, rgb
21 VK_FORMAT_R8G8_SSCALED , plain, 1, 1, ss8 , ss8 , , , xy01, rgb
22 VK_FORMAT_R8G8_UINT , plain, 1, 1, up8 , up8 , , , xy01, rgb
23 VK_FORMAT_R8G8_SINT , plain, 1, 1, sp8 , sp8 , , , xy01, rgb
24 VK_FORMAT_R8G8_SRGB , plain, 1, 1, un8 , un8 , , , xy01, srgb
25 VK_FORMAT_R8G8B8_UNORM , plain, 1, 1, un8 , un8 , un8 , , xyz1, rgb
26 VK_FORMAT_R8G8B8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , xyz1, rgb
27 VK_FORMAT_R8G8B8_USCALED , plain, 1, 1, us8 , us8 , us8 , , xyz1, rgb
28 VK_FORMAT_R8G8B8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , xyz1, rgb
29 VK_FORMAT_R8G8B8_UINT , plain, 1, 1, up8 , up8 , up8 , , xyz1, rgb
30 VK_FORMAT_R8G8B8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , xyz1, rgb
31 VK_FORMAT_R8G8B8_SRGB , plain, 1, 1, un8 , un8 , un8 , , xyz1, srgb
32 VK_FORMAT_B8G8R8_UNORM , plain, 1, 1, un8 , un8 , un8 , , zyx1, rgb
33 VK_FORMAT_B8G8R8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , , zyx1, rgb
34 VK_FORMAT_B8G8R8_USCALED , plain, 1, 1, us8 , us8 , us8 , , zyx1, rgb
35 VK_FORMAT_B8G8R8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , , zyx1, rgb
36 VK_FORMAT_B8G8R8_UINT , plain, 1, 1, up8 , up8 , up8 , , zyx1, rgb
37 VK_FORMAT_B8G8R8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , , zyx1, rgb
38 VK_FORMAT_B8G8R8_SRGB , plain, 1, 1, un8 , un8 , un8 , , zyx1, srgb
39 VK_FORMAT_R8G8B8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb
40 VK_FORMAT_R8G8B8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb
41 VK_FORMAT_R8G8B8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb
42 VK_FORMAT_R8G8B8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb
43 VK_FORMAT_R8G8B8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb
44 VK_FORMAT_R8G8B8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb
45 VK_FORMAT_R8G8B8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb
46 VK_FORMAT_B8G8R8A8_UNORM , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, rgb
47 VK_FORMAT_B8G8R8A8_SNORM , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , zyxw, rgb
48 VK_FORMAT_B8G8R8A8_USCALED , plain, 1, 1, us8 , us8 , us8 , us8 , zyxw, rgb
49 VK_FORMAT_B8G8R8A8_SSCALED , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , zyxw, rgb
50 VK_FORMAT_B8G8R8A8_UINT , plain, 1, 1, up8 , up8 , up8 , up8 , zyxw, rgb
51 VK_FORMAT_B8G8R8A8_SINT , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , zyxw, rgb
52 VK_FORMAT_B8G8R8A8_SRGB , plain, 1, 1, un8 , un8 , un8 , un8 , zyxw, srgb
53 VK_FORMAT_A8B8G8R8_UNORM_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, rgb
54 VK_FORMAT_A8B8G8R8_SNORM_PACK32 , plain, 1, 1, sn8 , sn8 , sn8 , sn8 , xyzw, rgb
55 VK_FORMAT_A8B8G8R8_USCALED_PACK32 , plain, 1, 1, us8 , us8 , us8 , us8 , xyzw, rgb
56 VK_FORMAT_A8B8G8R8_SSCALED_PACK32 , plain, 1, 1, ss8 , ss8 , ss8 , ss8 , xyzw, rgb
57 VK_FORMAT_A8B8G8R8_UINT_PACK32 , plain, 1, 1, up8 , up8 , up8 , up8 , xyzw, rgb
58 VK_FORMAT_A8B8G8R8_SINT_PACK32 , plain, 1, 1, sp8 , sp8 , sp8 , sp8 , xyzw, rgb
59 VK_FORMAT_A8B8G8R8_SRGB_PACK32 , plain, 1, 1, un8 , un8 , un8 , un8 , xyzw, srgb
60 VK_FORMAT_A2R10G10B10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , zyxw, rgb
61 VK_FORMAT_A2R10G10B10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , zyxw, rgb
62 VK_FORMAT_A2R10G10B10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , zyxw, rgb
63 VK_FORMAT_A2R10G10B10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , zyxw, rgb
64 VK_FORMAT_A2R10G10B10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , zyxw, rgb
65 VK_FORMAT_A2R10G10B10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , zyxw, rgb
66 VK_FORMAT_A2B10G10R10_UNORM_PACK32 , plain, 1, 1, un10, un10, un10, un2 , xyzw, rgb
67 VK_FORMAT_A2B10G10R10_SNORM_PACK32 , plain, 1, 1, sn10, sn10, sn10, sn2 , xyzw, rgb
68 VK_FORMAT_A2B10G10R10_USCALED_PACK32 , plain, 1, 1, us10, us10, us10, us2 , xyzw, rgb
69 VK_FORMAT_A2B10G10R10_SSCALED_PACK32 , plain, 1, 1, ss10, ss10, ss10, ss2 , xyzw, rgb
70 VK_FORMAT_A2B10G10R10_UINT_PACK32 , plain, 1, 1, up10, up10, up10, up2 , xyzw, rgb
71 VK_FORMAT_A2B10G10R10_SINT_PACK32 , plain, 1, 1, sp10, sp10, sp10, sp2 , xyzw, rgb
72 VK_FORMAT_R16_UNORM , plain, 1, 1, un16, , , , x001, rgb
73 VK_FORMAT_R16_SNORM , plain, 1, 1, sn16, , , , x001, rgb
74 VK_FORMAT_R16_USCALED , plain, 1, 1, us16, , , , x001, rgb
75 VK_FORMAT_R16_SSCALED , plain, 1, 1, ss16, , , , x001, rgb
76 VK_FORMAT_R16_UINT , plain, 1, 1, up16, , , , x001, rgb
77 VK_FORMAT_R16_SINT , plain, 1, 1, sp16, , , , x001, rgb
78 VK_FORMAT_R16_SFLOAT , plain, 1, 1, f16 , , , , x001, rgb
79 VK_FORMAT_R16G16_UNORM , plain, 1, 1, un16, un16, , , xy01, rgb
80 VK_FORMAT_R16G16_SNORM , plain, 1, 1, sn16, sn16, , , xy01, rgb
81 VK_FORMAT_R16G16_USCALED , plain, 1, 1, us16, us16, , , xy01, rgb
82 VK_FORMAT_R16G16_SSCALED , plain, 1, 1, ss16, ss16, , , xy01, rgb
83 VK_FORMAT_R16G16_UINT , plain, 1, 1, up16, up16, , , xy01, rgb
84 VK_FORMAT_R16G16_SINT , plain, 1, 1, sp16, sp16, , , xy01, rgb
85 VK_FORMAT_R16G16_SFLOAT , plain, 1, 1, f16 , f16 , , , xy01, rgb
86 VK_FORMAT_R16G16B16_UNORM , plain, 1, 1, un16, un16, un16, , xyz1, rgb
87 VK_FORMAT_R16G16B16_SNORM , plain, 1, 1, sn16, sn16, sn16, , xyz1, rgb
88 VK_FORMAT_R16G16B16_USCALED , plain, 1, 1, us16, us16, us16, , xyz1, rgb
89 VK_FORMAT_R16G16B16_SSCALED , plain, 1, 1, ss16, ss16, ss16, , xyz1, rgb
90 VK_FORMAT_R16G16B16_UINT , plain, 1, 1, up16, up16, up16, , xyz1, rgb
91 VK_FORMAT_R16G16B16_SINT , plain, 1, 1, sp16, sp16, sp16, , xyz1, rgb
92 VK_FORMAT_R16G16B16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , , xyz1, rgb
93 VK_FORMAT_R16G16B16A16_UNORM , plain, 1, 1, un16, un16, un16, un16, xyzw, rgb
94 VK_FORMAT_R16G16B16A16_SNORM , plain, 1, 1, sn16, sn16, sn16, sn16, xyzw, rgb
95 VK_FORMAT_R16G16B16A16_USCALED , plain, 1, 1, us16, us16, us16, us16, xyzw, rgb
96 VK_FORMAT_R16G16B16A16_SSCALED , plain, 1, 1, ss16, ss16, ss16, ss16, xyzw, rgb
97 VK_FORMAT_R16G16B16A16_UINT , plain, 1, 1, up16, up16, up16, up16, xyzw, rgb
98 VK_FORMAT_R16G16B16A16_SINT , plain, 1, 1, sp16, sp16, sp16, sp16, xyzw, rgb
99 VK_FORMAT_R16G16B16A16_SFLOAT , plain, 1, 1, f16 , f16 , f16 , f16 , xyzw, rgb
100 VK_FORMAT_R32_UINT , plain, 1, 1, up32, , , , x001, rgb
101 VK_FORMAT_R32_SINT , plain, 1, 1, sp32, , , , x001, rgb
102 VK_FORMAT_R32_SFLOAT , plain, 1, 1, f32 , , , , x001, rgb
103 VK_FORMAT_R32G32_UINT , plain, 1, 1, up32, up32, , , xy01, rgb
104 VK_FORMAT_R32G32_SINT , plain, 1, 1, sp32, sp32, , , xy01, rgb
105 VK_FORMAT_R32G32_SFLOAT , plain, 1, 1, f32 , f32 , , , xy01, rgb
106 VK_FORMAT_R32G32B32_UINT , plain, 1, 1, up32, up32, up32, , xyz1, rgb
107 VK_FORMAT_R32G32B32_SINT , plain, 1, 1, sp32, sp32, sp32, , xyz1, rgb
108 VK_FORMAT_R32G32B32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , , xyz1, rgb
109 VK_FORMAT_R32G32B32A32_UINT , plain, 1, 1, up32, up32, up32, up32, xyzw, rgb
110 VK_FORMAT_R32G32B32A32_SINT , plain, 1, 1, sp32, sp32, sp32, sp32, xyzw, rgb
111 VK_FORMAT_R32G32B32A32_SFLOAT , plain, 1, 1, f32 , f32 , f32 , f32 , xyzw, rgb
112 VK_FORMAT_R64_UINT , plain, 1, 1, up64, , , , x001, rgb
113 VK_FORMAT_R64_SINT , plain, 1, 1, sp64, , , , x001, rgb
114 VK_FORMAT_R64_SFLOAT , plain, 1, 1, f64 , , , , x001, rgb
115 VK_FORMAT_R64G64_UINT , plain, 1, 1, up64, up64, , , xy01, rgb
116 VK_FORMAT_R64G64_SINT , plain, 1, 1, sp64, sp64, , , xy01, rgb
117 VK_FORMAT_R64G64_SFLOAT , plain, 1, 1, f64 , f64 , , , xy01, rgb
118 VK_FORMAT_R64G64B64_UINT , plain, 1, 1, up64, up64, up64, , xyz1, rgb
119 VK_FORMAT_R64G64B64_SINT , plain, 1, 1, sp64, sp64, sp64, , xyz1, rgb
120 VK_FORMAT_R64G64B64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , , xyz1, rgb
121 VK_FORMAT_R64G64B64A64_UINT , plain, 1, 1, up64, up64, up64, up64, xyzw, rgb
122 VK_FORMAT_R64G64B64A64_SINT , plain, 1, 1, sp64, sp64, sp64, sp64, xyzw, rgb
123 VK_FORMAT_R64G64B64A64_SFLOAT , plain, 1, 1, f64 , f64 , f64 , f64 , xyzw, rgb
124 VK_FORMAT_B10G11R11_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb
125 VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 , other, 1, 1, x32 , , , , xyz1, rgb
126 VK_FORMAT_D16_UNORM , plain, 1, 1, un16, , , , x___, zs
127 VK_FORMAT_X8_D24_UNORM_PACK32 , plain, 1, 1, un24, x8 , , , x___, zs
128 VK_FORMAT_D32_SFLOAT , plain, 1, 1, f32 , , , , x___, zs
129 VK_FORMAT_S8_UINT , plain, 1, 1, up8 , , , , _x__, zs
130 VK_FORMAT_D16_UNORM_S8_UINT , plain, 1, 1, un16, up8 , , , xy__, zs
131 VK_FORMAT_D24_UNORM_S8_UINT , plain, 1, 1, un24, up8 , , , xy__, zs
132 VK_FORMAT_D32_SFLOAT_S8_UINT , plain, 1, 1, f32 , up8 , , , xy__, zs
133 VK_FORMAT_BC1_RGB_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, rgb
134 VK_FORMAT_BC1_RGB_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyz1, srgb
135 VK_FORMAT_BC1_RGBA_UNORM_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, rgb
136 VK_FORMAT_BC1_RGBA_SRGB_BLOCK , s3tc, 4, 4, x64 , , , , xyzw, srgb
137 VK_FORMAT_BC2_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb
138 VK_FORMAT_BC2_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb
139 VK_FORMAT_BC3_UNORM_BLOCK , s3tc, 4, 4, x128, , , , xyzw, rgb
140 VK_FORMAT_BC3_SRGB_BLOCK , s3tc, 4, 4, x128, , , , xyzw, srgb
141 VK_FORMAT_BC4_UNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb
142 VK_FORMAT_BC4_SNORM_BLOCK , rgtc, 4, 4, x64, , , , x001, rgb
143 VK_FORMAT_BC5_UNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb
144 VK_FORMAT_BC5_SNORM_BLOCK , rgtc, 4, 4, x128, , , , xy01, rgb
145 VK_FORMAT_BC6H_UFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb
146 VK_FORMAT_BC6H_SFLOAT_BLOCK , bptc, 4, 4, x128, , , , xyz1, rgb
147 VK_FORMAT_BC7_UNORM_BLOCK , bptc, 4, 4, x128, , , , xyzw, rgb
148 VK_FORMAT_BC7_SRGB_BLOCK , bptc, 4, 4, x128, , , , xyzw, srgb
149 VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK,
150 VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK,
151 VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK,
152 VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK,
153 VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
154 VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK,
155 VK_FORMAT_EAC_R11_UNORM_BLOCK,
156 VK_FORMAT_EAC_R11_SNORM_BLOCK,
157 VK_FORMAT_EAC_R11G11_UNORM_BLOCK,
158 VK_FORMAT_EAC_R11G11_SNORM_BLOCK,
159 VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
160 VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
161 VK_FORMAT_ASTC_5x4_UNORM_BLOCK,
162 VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
163 VK_FORMAT_ASTC_5x5_UNORM_BLOCK,
164 VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
165 VK_FORMAT_ASTC_6x5_UNORM_BLOCK,
166 VK_FORMAT_ASTC_6x5_SRGB_BLOCK,
167 VK_FORMAT_ASTC_6x6_UNORM_BLOCK,
168 VK_FORMAT_ASTC_6x6_SRGB_BLOCK,
169 VK_FORMAT_ASTC_8x5_UNORM_BLOCK,
170 VK_FORMAT_ASTC_8x5_SRGB_BLOCK,
171 VK_FORMAT_ASTC_8x6_UNORM_BLOCK,
172 VK_FORMAT_ASTC_8x6_SRGB_BLOCK,
173 VK_FORMAT_ASTC_8x8_UNORM_BLOCK,
174 VK_FORMAT_ASTC_8x8_SRGB_BLOCK,
175 VK_FORMAT_ASTC_10x5_UNORM_BLOCK,
176 VK_FORMAT_ASTC_10x5_SRGB_BLOCK,
177 VK_FORMAT_ASTC_10x6_UNORM_BLOCK,
178 VK_FORMAT_ASTC_10x6_SRGB_BLOCK,
179 VK_FORMAT_ASTC_10x8_UNORM_BLOCK,
180 VK_FORMAT_ASTC_10x8_SRGB_BLOCK,
181 VK_FORMAT_ASTC_10x10_UNORM_BLOCK,
182 VK_FORMAT_ASTC_10x10_SRGB_BLOCK,
183 VK_FORMAT_ASTC_12x10_UNORM_BLOCK,
184 VK_FORMAT_ASTC_12x10_SRGB_BLOCK,
185 VK_FORMAT_ASTC_12x12_UNORM_BLOCK,
186 VK_FORMAT_ASTC_12x12_SRGB_BLOCK,

384
src/amd/vulkan/vk_format_parse.py Executable file
View File

@ -0,0 +1,384 @@
#!/usr/bin/env python
'''
/**************************************************************************
*
* Copyright 2009 VMware, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
'''
VOID, UNSIGNED, SIGNED, FIXED, FLOAT = range(5)
SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_0, SWIZZLE_1, SWIZZLE_NONE, = range(7)
PLAIN = 'plain'
SCALED = 'scaled'
RGB = 'rgb'
SRGB = 'srgb'
YUV = 'yuv'
ZS = 'zs'
def is_pot(x):
return (x & (x - 1)) == 0
VERY_LARGE = 99999999999999999999999
class Channel:
'''Describe the channel of a color channel.'''
def __init__(self, type, norm, pure, scaled, size, name = ''):
self.type = type
self.norm = norm
self.pure = pure
self.size = size
self.scaled = scaled
self.sign = type in (SIGNED, FIXED, FLOAT)
self.name = name
def __str__(self):
s = str(self.type)
if self.norm:
s += 'n'
if self.pure:
s += 'p'
if self.scaled:
s += 's'
s += str(self.size)
return s
def __eq__(self, other):
return self.type == other.type and self.norm == other.norm and self.pure == other.pure and self.size == other.size and self.scaled == other.scaled
def max(self):
'''Maximum representable number.'''
if self.type == FLOAT:
return VERY_LARGE
if self.type == FIXED:
return (1 << (self.size/2)) - 1
if self.norm:
return 1
if self.type == UNSIGNED:
return (1 << self.size) - 1
if self.type == SIGNED:
return (1 << (self.size - 1)) - 1
assert False
def min(self):
'''Minimum representable number.'''
if self.type == FLOAT:
return -VERY_LARGE
if self.type == FIXED:
return -(1 << (self.size/2))
if self.type == UNSIGNED:
return 0
if self.norm:
return -1
if self.type == SIGNED:
return -(1 << (self.size - 1))
assert False
class Format:
'''Describe a pixel format.'''
def __init__(self, name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace):
self.name = name
self.layout = layout
self.block_width = block_width
self.block_height = block_height
self.le_channels = le_channels
self.le_swizzles = le_swizzles
self.be_channels = be_channels
self.be_swizzles = be_swizzles
self.name = name
self.colorspace = colorspace
def __str__(self):
return self.name
def short_name(self):
'''Make up a short norm for a format, suitable to be used as suffix in
function names.'''
name = self.name
if name.startswith('VK_FORMAT_'):
name = name[len('VK_FORMAT_'):]
name = name.lower()
return name
def block_size(self):
size = 0
for channel in self.le_channels:
size += channel.size
return size
def nr_channels(self):
nr_channels = 0
for channel in self.le_channels:
if channel.size:
nr_channels += 1
return nr_channels
def array_element(self):
if self.layout != PLAIN:
return None
ref_channel = self.le_channels[0]
if ref_channel.type == VOID:
ref_channel = self.le_channels[1]
for channel in self.le_channels:
if channel.size and (channel.size != ref_channel.size or channel.size % 8):
return None
if channel.type != VOID:
if channel.type != ref_channel.type:
return None
if channel.norm != ref_channel.norm:
return None
if channel.pure != ref_channel.pure:
return None
if channel.scaled != ref_channel.scaled:
return None
return ref_channel
def is_array(self):
return self.array_element() != None
def is_mixed(self):
if self.layout != PLAIN:
return False
ref_channel = self.le_channels[0]
if ref_channel.type == VOID:
ref_channel = self.le_channels[1]
for channel in self.le_channels[1:]:
if channel.type != VOID:
if channel.type != ref_channel.type:
return True
if channel.norm != ref_channel.norm:
return True
if channel.pure != ref_channel.pure:
return True
if channel.scaled != ref_channel.scaled:
return True
return False
def is_pot(self):
return is_pot(self.block_size())
def is_int(self):
if self.layout != PLAIN:
return False
for channel in self.le_channels:
if channel.type not in (VOID, UNSIGNED, SIGNED):
return False
return True
def is_float(self):
if self.layout != PLAIN:
return False
for channel in self.le_channels:
if channel.type not in (VOID, FLOAT):
return False
return True
def is_bitmask(self):
if self.layout != PLAIN:
return False
if self.block_size() not in (8, 16, 32):
return False
for channel in self.le_channels:
if channel.type not in (VOID, UNSIGNED, SIGNED):
return False
return True
def is_pure_color(self):
if self.layout != PLAIN or self.colorspace == ZS:
return False
pures = [channel.pure
for channel in self.le_channels
if channel.type != VOID]
for x in pures:
assert x == pures[0]
return pures[0]
def channel_type(self):
types = [channel.type
for channel in self.le_channels
if channel.type != VOID]
for x in types:
assert x == types[0]
return types[0]
def is_pure_signed(self):
return self.is_pure_color() and self.channel_type() == SIGNED
def is_pure_unsigned(self):
return self.is_pure_color() and self.channel_type() == UNSIGNED
def has_channel(self, id):
return self.le_swizzles[id] != SWIZZLE_NONE
def has_depth(self):
return self.colorspace == ZS and self.has_channel(0)
def has_stencil(self):
return self.colorspace == ZS and self.has_channel(1)
def stride(self):
return self.block_size()/8
_type_parse_map = {
'': VOID,
'x': VOID,
'u': UNSIGNED,
's': SIGNED,
'h': FIXED,
'f': FLOAT,
}
_swizzle_parse_map = {
'x': SWIZZLE_X,
'y': SWIZZLE_Y,
'z': SWIZZLE_Z,
'w': SWIZZLE_W,
'0': SWIZZLE_0,
'1': SWIZZLE_1,
'_': SWIZZLE_NONE,
}
def _parse_channels(fields, layout, colorspace, swizzles):
if layout == PLAIN:
names = ['']*4
if colorspace in (RGB, SRGB):
for i in range(4):
swizzle = swizzles[i]
if swizzle < 4:
names[swizzle] += 'rgba'[i]
elif colorspace == ZS:
for i in range(4):
swizzle = swizzles[i]
if swizzle < 4:
names[swizzle] += 'zs'[i]
else:
assert False
for i in range(4):
if names[i] == '':
names[i] = 'x'
else:
names = ['x', 'y', 'z', 'w']
channels = []
for i in range(0, 4):
field = fields[i]
if field:
type = _type_parse_map[field[0]]
if field[1] == 'n':
norm = True
pure = False
scaled = False
size = int(field[2:])
elif field[1] == 'p':
pure = True
norm = False
scaled = False
size = int(field[2:])
elif field[1] == 's':
pure = False
norm = False
scaled = True
size = int(field[2:])
else:
norm = False
pure = False
scaled = False
size = int(field[1:])
else:
type = VOID
norm = False
pure = False
scaled = False
size = 0
channel = Channel(type, norm, pure, scaled, size, names[i])
channels.append(channel)
return channels
def parse(filename):
'''Parse the format description in CSV format in terms of the
Channel and Format classes above.'''
stream = open(filename)
formats = []
for line in stream:
try:
comment = line.index('#')
except ValueError:
pass
else:
line = line[:comment]
line = line.strip()
if not line:
continue
fields = [field.strip() for field in line.split(',')]
if len (fields) < 10:
continue
if len (fields) == 10:
fields += fields[4:9]
assert len (fields) == 15
name = fields[0]
layout = fields[1]
block_width, block_height = map(int, fields[2:4])
colorspace = fields[9]
le_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[8]]
le_channels = _parse_channels(fields[4:8], layout, colorspace, le_swizzles)
be_swizzles = [_swizzle_parse_map[swizzle] for swizzle in fields[14]]
be_channels = _parse_channels(fields[10:14], layout, colorspace, be_swizzles)
le_shift = 0
for channel in le_channels:
channel.shift = le_shift
le_shift += channel.size
be_shift = 0
for channel in be_channels[3::-1]:
channel.shift = be_shift
be_shift += channel.size
assert le_shift == be_shift
for i in range(4):
assert (le_swizzles[i] != SWIZZLE_NONE) == (be_swizzles[i] != SWIZZLE_NONE)
format = Format(name, layout, block_width, block_height, le_channels, le_swizzles, be_channels, be_swizzles, colorspace)
formats.append(format)
return formats

173
src/amd/vulkan/vk_format_table.py Executable file
View File

@ -0,0 +1,173 @@
#!/usr/bin/env python
CopyRight = '''
/**************************************************************************
*
* Copyright 2010 VMware, Inc.
* All Rights Reserved.
*
* 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, sub license, 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 NON-INFRINGEMENT.
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
*
**************************************************************************/
'''
import sys
from vk_format_parse import *
def layout_map(layout):
return 'VK_FORMAT_LAYOUT_' + str(layout).upper()
def colorspace_map(colorspace):
return 'VK_FORMAT_COLORSPACE_' + str(colorspace).upper()
colorspace_channels_map = {
'rgb': ['r', 'g', 'b', 'a'],
'srgb': ['sr', 'sg', 'sb', 'a'],
'zs': ['z', 's'],
'yuv': ['y', 'u', 'v'],
}
type_map = {
VOID: "VK_FORMAT_TYPE_VOID",
UNSIGNED: "VK_FORMAT_TYPE_UNSIGNED",
SIGNED: "VK_FORMAT_TYPE_SIGNED",
FIXED: "VK_FORMAT_TYPE_FIXED",
FLOAT: "VK_FORMAT_TYPE_FLOAT",
}
def bool_map(value):
if value:
return "true"
else:
return "false"
swizzle_map = {
SWIZZLE_X: "VK_SWIZZLE_X",
SWIZZLE_Y: "VK_SWIZZLE_Y",
SWIZZLE_Z: "VK_SWIZZLE_Z",
SWIZZLE_W: "VK_SWIZZLE_W",
SWIZZLE_0: "VK_SWIZZLE_0",
SWIZZLE_1: "VK_SWIZZLE_1",
SWIZZLE_NONE: "VK_SWIZZLE_NONE",
}
def print_channels(format, func):
if format.nr_channels() <= 1:
func(format.le_channels, format.le_swizzles)
else:
print '#ifdef PIPE_ARCH_BIG_ENDIAN'
func(format.be_channels, format.be_swizzles)
print '#else'
func(format.le_channels, format.le_swizzles)
print '#endif'
def write_format_table(formats):
print '/* This file is autogenerated by u_format_table.py from u_format.csv. Do not edit directly. */'
print
# This will print the copyright message on the top of this file
print CopyRight.strip()
print
print '#include "stdbool.h"'
print '#include "vk_format.h"'
print
def do_channel_array(channels, swizzles):
print " {"
for i in range(4):
channel = channels[i]
if i < 3:
sep = ","
else:
sep = ""
if channel.size:
print " {%s, %s, %s, %s, %u, %u}%s\t/* %s = %s */" % (type_map[channel.type], bool_map(channel.norm), bool_map(channel.pure), bool_map(channel.scaled), channel.size, channel.shift, sep, "xyzw"[i], channel.name)
else:
print " {0, 0, 0, 0, 0}%s" % (sep,)
print " },"
def do_swizzle_array(channels, swizzles):
print " {"
for i in range(4):
swizzle = swizzles[i]
if i < 3:
sep = ","
else:
sep = ""
try:
comment = colorspace_channels_map[format.colorspace][i]
except (KeyError, IndexError):
comment = 'ignored'
print " %s%s\t/* %s */" % (swizzle_map[swizzle], sep, comment)
print " },"
for format in formats:
print 'const struct vk_format_description'
print 'vk_format_%s_description = {' % (format.short_name(),)
print " %s," % (format.name,)
print " \"%s\"," % (format.name,)
print " \"%s\"," % (format.short_name(),)
print " {%u, %u, %u},\t/* block */" % (format.block_width, format.block_height, format.block_size())
print " %s," % (layout_map(format.layout),)
print " %u,\t/* nr_channels */" % (format.nr_channels(),)
print " %s,\t/* is_array */" % (bool_map(format.is_array()),)
print " %s,\t/* is_bitmask */" % (bool_map(format.is_bitmask()),)
print " %s,\t/* is_mixed */" % (bool_map(format.is_mixed()),)
print_channels(format, do_channel_array)
print_channels(format, do_swizzle_array)
print " %s," % (colorspace_map(format.colorspace),)
print "};"
print
print "const struct vk_format_description *"
print "vk_format_description(VkFormat format)"
print "{"
print " if (format > VK_FORMAT_END_RANGE) {"
print " return NULL;"
print " }"
print
print " switch (format) {"
for format in formats:
print " case %s:" % format.name
print " return &vk_format_%s_description;" % (format.short_name(),)
print " default:"
print " return NULL;"
print " }"
print "}"
print
def main():
formats = []
for arg in sys.argv[1:]:
formats.extend(parse(arg))
write_format_table(formats)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,297 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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 <stdio.h>
#include "radv_amdgpu_bo.h"
#include <amdgpu.h>
#include <amdgpu_drm.h>
#include <inttypes.h>
static void radv_amdgpu_winsys_bo_destroy(struct radeon_winsys_bo *_bo)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
if (bo->ws->debug_all_bos) {
pthread_mutex_lock(&bo->ws->global_bo_list_lock);
LIST_DEL(&bo->global_list_item);
bo->ws->num_buffers--;
pthread_mutex_unlock(&bo->ws->global_bo_list_lock);
}
amdgpu_bo_va_op(bo->bo, 0, bo->size, bo->va, 0, AMDGPU_VA_OP_UNMAP);
amdgpu_va_range_free(bo->va_handle);
amdgpu_bo_free(bo->bo);
FREE(bo);
}
static void radv_amdgpu_add_buffer_to_global_list(struct radv_amdgpu_winsys_bo *bo)
{
struct radv_amdgpu_winsys *ws = bo->ws;
if (bo->ws->debug_all_bos) {
pthread_mutex_lock(&ws->global_bo_list_lock);
LIST_ADDTAIL(&bo->global_list_item, &ws->global_bo_list);
ws->num_buffers++;
pthread_mutex_unlock(&ws->global_bo_list_lock);
}
}
static struct radeon_winsys_bo *
radv_amdgpu_winsys_bo_create(struct radeon_winsys *_ws,
uint64_t size,
unsigned alignment,
enum radeon_bo_domain initial_domain,
unsigned flags)
{
struct radv_amdgpu_winsys *ws = radv_amdgpu_winsys(_ws);
struct radv_amdgpu_winsys_bo *bo;
struct amdgpu_bo_alloc_request request = {0};
amdgpu_bo_handle buf_handle;
uint64_t va = 0;
amdgpu_va_handle va_handle;
int r;
bo = CALLOC_STRUCT(radv_amdgpu_winsys_bo);
if (!bo) {
return NULL;
}
request.alloc_size = size;
request.phys_alignment = alignment;
if (initial_domain & RADEON_DOMAIN_VRAM)
request.preferred_heap |= AMDGPU_GEM_DOMAIN_VRAM;
if (initial_domain & RADEON_DOMAIN_GTT)
request.preferred_heap |= AMDGPU_GEM_DOMAIN_GTT;
if (flags & RADEON_FLAG_CPU_ACCESS)
request.flags |= AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
if (flags & RADEON_FLAG_NO_CPU_ACCESS)
request.flags |= AMDGPU_GEM_CREATE_NO_CPU_ACCESS;
if (flags & RADEON_FLAG_GTT_WC)
request.flags |= AMDGPU_GEM_CREATE_CPU_GTT_USWC;
r = amdgpu_bo_alloc(ws->dev, &request, &buf_handle);
if (r) {
fprintf(stderr, "amdgpu: Failed to allocate a buffer:\n");
fprintf(stderr, "amdgpu: size : %"PRIu64" bytes\n", size);
fprintf(stderr, "amdgpu: alignment : %u bytes\n", alignment);
fprintf(stderr, "amdgpu: domains : %u\n", initial_domain);
goto error_bo_alloc;
}
r = amdgpu_va_range_alloc(ws->dev, amdgpu_gpu_va_range_general,
size, alignment, 0, &va, &va_handle, 0);
if (r)
goto error_va_alloc;
r = amdgpu_bo_va_op(buf_handle, 0, size, va, 0, AMDGPU_VA_OP_MAP);
if (r)
goto error_va_map;
bo->bo = buf_handle;
bo->va = va;
bo->va_handle = va_handle;
bo->initial_domain = initial_domain;
bo->size = size;
bo->is_shared = false;
bo->ws = ws;
radv_amdgpu_add_buffer_to_global_list(bo);
return (struct radeon_winsys_bo *)bo;
error_va_map:
amdgpu_va_range_free(va_handle);
error_va_alloc:
amdgpu_bo_free(buf_handle);
error_bo_alloc:
FREE(bo);
return NULL;
}
static uint64_t radv_amdgpu_winsys_bo_get_va(struct radeon_winsys_bo *_bo)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
return bo->va;
}
static void *
radv_amdgpu_winsys_bo_map(struct radeon_winsys_bo *_bo)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
int ret;
void *data;
ret = amdgpu_bo_cpu_map(bo->bo, &data);
if (ret)
return NULL;
return data;
}
static void
radv_amdgpu_winsys_bo_unmap(struct radeon_winsys_bo *_bo)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
amdgpu_bo_cpu_unmap(bo->bo);
}
static struct radeon_winsys_bo *
radv_amdgpu_winsys_bo_from_fd(struct radeon_winsys *_ws,
int fd, unsigned *stride,
unsigned *offset)
{
struct radv_amdgpu_winsys *ws = radv_amdgpu_winsys(_ws);
struct radv_amdgpu_winsys_bo *bo;
uint64_t va;
amdgpu_va_handle va_handle;
enum amdgpu_bo_handle_type type = amdgpu_bo_handle_type_dma_buf_fd;
struct amdgpu_bo_import_result result = {0};
struct amdgpu_bo_info info = {0};
enum radeon_bo_domain initial = 0;
int r;
bo = CALLOC_STRUCT(radv_amdgpu_winsys_bo);
if (!bo)
return NULL;
r = amdgpu_bo_import(ws->dev, type, fd, &result);
if (r)
goto error;
r = amdgpu_bo_query_info(result.buf_handle, &info);
if (r)
goto error_query;
r = amdgpu_va_range_alloc(ws->dev, amdgpu_gpu_va_range_general,
result.alloc_size, 1 << 20, 0, &va, &va_handle, 0);
if (r)
goto error_query;
r = amdgpu_bo_va_op(result.buf_handle, 0, result.alloc_size, va, 0, AMDGPU_VA_OP_MAP);
if (r)
goto error_va_map;
if (info.preferred_heap & AMDGPU_GEM_DOMAIN_VRAM)
initial |= RADEON_DOMAIN_VRAM;
if (info.preferred_heap & AMDGPU_GEM_DOMAIN_GTT)
initial |= RADEON_DOMAIN_GTT;
bo->bo = result.buf_handle;
bo->va = va;
bo->va_handle = va_handle;
bo->initial_domain = initial;
bo->size = result.alloc_size;
bo->is_shared = true;
return (struct radeon_winsys_bo *)bo;
error_va_map:
amdgpu_va_range_free(va_handle);
error_query:
amdgpu_bo_free(result.buf_handle);
error:
FREE(bo);
return NULL;
}
static bool
radv_amdgpu_winsys_get_fd(struct radeon_winsys *_ws,
struct radeon_winsys_bo *_bo,
int *fd)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
enum amdgpu_bo_handle_type type = amdgpu_bo_handle_type_dma_buf_fd;
int r;
unsigned handle;
r = amdgpu_bo_export(bo->bo, type, &handle);
if (r)
return false;
*fd = (int)handle;
bo->is_shared = true;
return true;
}
static unsigned radv_eg_tile_split_rev(unsigned eg_tile_split)
{
switch (eg_tile_split) {
case 64: return 0;
case 128: return 1;
case 256: return 2;
case 512: return 3;
default:
case 1024: return 4;
case 2048: return 5;
case 4096: return 6;
}
}
static void
radv_amdgpu_winsys_bo_set_metadata(struct radeon_winsys_bo *_bo,
struct radeon_bo_metadata *md)
{
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
struct amdgpu_bo_metadata metadata = {0};
uint32_t tiling_flags = 0;
if (md->macrotile == RADEON_LAYOUT_TILED)
tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, 4); /* 2D_TILED_THIN1 */
else if (md->microtile == RADEON_LAYOUT_TILED)
tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, 2); /* 1D_TILED_THIN1 */
else
tiling_flags |= AMDGPU_TILING_SET(ARRAY_MODE, 1); /* LINEAR_ALIGNED */
tiling_flags |= AMDGPU_TILING_SET(PIPE_CONFIG, md->pipe_config);
tiling_flags |= AMDGPU_TILING_SET(BANK_WIDTH, util_logbase2(md->bankw));
tiling_flags |= AMDGPU_TILING_SET(BANK_HEIGHT, util_logbase2(md->bankh));
if (md->tile_split)
tiling_flags |= AMDGPU_TILING_SET(TILE_SPLIT, radv_eg_tile_split_rev(md->tile_split));
tiling_flags |= AMDGPU_TILING_SET(MACRO_TILE_ASPECT, util_logbase2(md->mtilea));
tiling_flags |= AMDGPU_TILING_SET(NUM_BANKS, util_logbase2(md->num_banks)-1);
if (md->scanout)
tiling_flags |= AMDGPU_TILING_SET(MICRO_TILE_MODE, 0); /* DISPLAY_MICRO_TILING */
else
tiling_flags |= AMDGPU_TILING_SET(MICRO_TILE_MODE, 1); /* THIN_MICRO_TILING */
metadata.tiling_info = tiling_flags;
metadata.size_metadata = md->size_metadata;
memcpy(metadata.umd_metadata, md->metadata, sizeof(md->metadata));
amdgpu_bo_set_metadata(bo->bo, &metadata);
}
void radv_amdgpu_bo_init_functions(struct radv_amdgpu_winsys *ws)
{
ws->base.buffer_create = radv_amdgpu_winsys_bo_create;
ws->base.buffer_destroy = radv_amdgpu_winsys_bo_destroy;
ws->base.buffer_get_va = radv_amdgpu_winsys_bo_get_va;
ws->base.buffer_map = radv_amdgpu_winsys_bo_map;
ws->base.buffer_unmap = radv_amdgpu_winsys_bo_unmap;
ws->base.buffer_from_fd = radv_amdgpu_winsys_bo_from_fd;
ws->base.buffer_get_fd = radv_amdgpu_winsys_get_fd;
ws->base.buffer_set_metadata = radv_amdgpu_winsys_bo_set_metadata;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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.
*/
#pragma once
#include "radv_amdgpu_winsys.h"
struct radv_amdgpu_winsys_bo {
amdgpu_bo_handle bo;
amdgpu_va_handle va_handle;
uint64_t va;
enum radeon_bo_domain initial_domain;
uint64_t size;
bool is_shared;
struct radv_amdgpu_winsys *ws;
struct list_head global_list_item;
};
static inline
struct radv_amdgpu_winsys_bo *radv_amdgpu_winsys_bo(struct radeon_winsys_bo *bo)
{
return (struct radv_amdgpu_winsys_bo *)bo;
}
void radv_amdgpu_bo_init_functions(struct radv_amdgpu_winsys *ws);

View File

@ -0,0 +1,778 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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 <stdlib.h>
#include <amdgpu.h>
#include <amdgpu_drm.h>
#include <assert.h>
#include "amdgpu_id.h"
#include "radv_radeon_winsys.h"
#include "radv_amdgpu_cs.h"
#include "radv_amdgpu_bo.h"
#include "sid.h"
struct radv_amdgpu_cs {
struct radeon_winsys_cs base;
struct radv_amdgpu_winsys *ws;
struct amdgpu_cs_ib_info ib;
struct radeon_winsys_bo *ib_buffer;
uint8_t *ib_mapped;
unsigned max_num_buffers;
unsigned num_buffers;
amdgpu_bo_handle *handles;
uint8_t *priorities;
struct radeon_winsys_bo **old_ib_buffers;
unsigned num_old_ib_buffers;
unsigned max_num_old_ib_buffers;
unsigned *ib_size_ptr;
bool failed;
bool is_chained;
int buffer_hash_table[1024];
};
static inline struct radv_amdgpu_cs *
radv_amdgpu_cs(struct radeon_winsys_cs *base)
{
return (struct radv_amdgpu_cs*)base;
}
static struct radeon_winsys_fence *radv_amdgpu_create_fence()
{
struct radv_amdgpu_cs_fence *fence = calloc(1, sizeof(struct amdgpu_cs_fence));
return (struct radeon_winsys_fence*)fence;
}
static void radv_amdgpu_destroy_fence(struct radeon_winsys_fence *_fence)
{
struct amdgpu_cs_fence *fence = (struct amdgpu_cs_fence *)_fence;
free(fence);
}
static bool radv_amdgpu_fence_wait(struct radeon_winsys *_ws,
struct radeon_winsys_fence *_fence,
bool absolute,
uint64_t timeout)
{
struct amdgpu_cs_fence *fence = (struct amdgpu_cs_fence *)_fence;
unsigned flags = absolute ? AMDGPU_QUERY_FENCE_TIMEOUT_IS_ABSOLUTE : 0;
int r;
uint32_t expired = 0;
/* Now use the libdrm query. */
r = amdgpu_cs_query_fence_status(fence,
timeout,
flags,
&expired);
if (r) {
fprintf(stderr, "amdgpu: radv_amdgpu_cs_query_fence_status failed.\n");
return false;
}
if (expired) {
return true;
}
return false;
}
static void radv_amdgpu_cs_destroy(struct radeon_winsys_cs *rcs)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(rcs);
if (cs->ib_buffer)
cs->ws->base.buffer_destroy(cs->ib_buffer);
else
free(cs->base.buf);
for (unsigned i = 0; i < cs->num_old_ib_buffers; ++i)
cs->ws->base.buffer_destroy(cs->old_ib_buffers[i]);
free(cs->old_ib_buffers);
free(cs->handles);
free(cs->priorities);
free(cs);
}
static boolean radv_amdgpu_init_cs(struct radv_amdgpu_cs *cs,
enum ring_type ring_type)
{
for (int i = 0; i < ARRAY_SIZE(cs->buffer_hash_table); ++i) {
cs->buffer_hash_table[i] = -1;
}
return true;
}
static struct radeon_winsys_cs *
radv_amdgpu_cs_create(struct radeon_winsys *ws,
enum ring_type ring_type)
{
struct radv_amdgpu_cs *cs;
uint32_t ib_size = 20 * 1024 * 4;
cs = calloc(1, sizeof(struct radv_amdgpu_cs));
if (!cs)
return NULL;
cs->ws = radv_amdgpu_winsys(ws);
radv_amdgpu_init_cs(cs, RING_GFX);
if (cs->ws->use_ib_bos) {
cs->ib_buffer = ws->buffer_create(ws, ib_size, 0,
RADEON_DOMAIN_GTT,
RADEON_FLAG_CPU_ACCESS);
if (!cs->ib_buffer) {
free(cs);
return NULL;
}
cs->ib_mapped = ws->buffer_map(cs->ib_buffer);
if (!cs->ib_mapped) {
ws->buffer_destroy(cs->ib_buffer);
free(cs);
return NULL;
}
cs->ib.ib_mc_address = radv_amdgpu_winsys_bo(cs->ib_buffer)->va;
cs->base.buf = (uint32_t *)cs->ib_mapped;
cs->base.max_dw = ib_size / 4 - 4;
cs->ib_size_ptr = &cs->ib.size;
cs->ib.size = 0;
ws->cs_add_buffer(&cs->base, cs->ib_buffer, 8);
} else {
cs->base.buf = malloc(16384);
cs->base.max_dw = 4096;
if (!cs->base.buf) {
free(cs);
return NULL;
}
}
return &cs->base;
}
static void radv_amdgpu_cs_grow(struct radeon_winsys_cs *_cs, size_t min_size)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(_cs);
uint64_t ib_size = MAX2(min_size * 4 + 16, cs->base.max_dw * 4 * 2);
/* max that fits in the chain size field. */
ib_size = MIN2(ib_size, 0xfffff);
if (cs->failed) {
cs->base.cdw = 0;
return;
}
if (!cs->ws->use_ib_bos) {
uint32_t *new_buf = realloc(cs->base.buf, ib_size);
if (new_buf) {
cs->base.buf = new_buf;
cs->base.max_dw = ib_size / 4;
} else {
cs->failed = true;
cs->base.cdw = 0;
}
return;
}
while (!cs->base.cdw || (cs->base.cdw & 7) != 4)
cs->base.buf[cs->base.cdw++] = 0xffff1000;
*cs->ib_size_ptr |= cs->base.cdw + 4;
if (cs->num_old_ib_buffers == cs->max_num_old_ib_buffers) {
cs->max_num_old_ib_buffers = MAX2(1, cs->max_num_old_ib_buffers * 2);
cs->old_ib_buffers = realloc(cs->old_ib_buffers,
cs->max_num_old_ib_buffers * sizeof(void*));
}
cs->old_ib_buffers[cs->num_old_ib_buffers++] = cs->ib_buffer;
cs->ib_buffer = cs->ws->base.buffer_create(&cs->ws->base, ib_size, 0,
RADEON_DOMAIN_GTT,
RADEON_FLAG_CPU_ACCESS);
if (!cs->ib_buffer) {
cs->base.cdw = 0;
cs->failed = true;
cs->ib_buffer = cs->old_ib_buffers[--cs->num_old_ib_buffers];
}
cs->ib_mapped = cs->ws->base.buffer_map(cs->ib_buffer);
if (!cs->ib_mapped) {
cs->ws->base.buffer_destroy(cs->ib_buffer);
cs->base.cdw = 0;
cs->failed = true;
cs->ib_buffer = cs->old_ib_buffers[--cs->num_old_ib_buffers];
}
cs->ws->base.cs_add_buffer(&cs->base, cs->ib_buffer, 8);
cs->base.buf[cs->base.cdw++] = PKT3(PKT3_INDIRECT_BUFFER_CIK, 2, 0);
cs->base.buf[cs->base.cdw++] = radv_amdgpu_winsys_bo(cs->ib_buffer)->va;
cs->base.buf[cs->base.cdw++] = radv_amdgpu_winsys_bo(cs->ib_buffer)->va >> 32;
cs->ib_size_ptr = cs->base.buf + cs->base.cdw;
cs->base.buf[cs->base.cdw++] = S_3F2_CHAIN(1) | S_3F2_VALID(1);
cs->base.buf = (uint32_t *)cs->ib_mapped;
cs->base.cdw = 0;
cs->base.max_dw = ib_size / 4 - 4;
}
static bool radv_amdgpu_cs_finalize(struct radeon_winsys_cs *_cs)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(_cs);
if (cs->ws->use_ib_bos) {
while (!cs->base.cdw || (cs->base.cdw & 7) != 0)
cs->base.buf[cs->base.cdw++] = 0xffff1000;
*cs->ib_size_ptr |= cs->base.cdw;
cs->is_chained = false;
}
return !cs->failed;
}
static void radv_amdgpu_cs_reset(struct radeon_winsys_cs *_cs)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(_cs);
cs->base.cdw = 0;
cs->failed = false;
for (unsigned i = 0; i < cs->num_buffers; ++i) {
unsigned hash = ((uintptr_t)cs->handles[i] >> 6) &
(ARRAY_SIZE(cs->buffer_hash_table) - 1);
cs->buffer_hash_table[hash] = -1;
}
cs->num_buffers = 0;
if (cs->ws->use_ib_bos) {
cs->ws->base.cs_add_buffer(&cs->base, cs->ib_buffer, 8);
for (unsigned i = 0; i < cs->num_old_ib_buffers; ++i)
cs->ws->base.buffer_destroy(cs->old_ib_buffers[i]);
cs->num_old_ib_buffers = 0;
cs->ib.ib_mc_address = radv_amdgpu_winsys_bo(cs->ib_buffer)->va;
cs->ib_size_ptr = &cs->ib.size;
cs->ib.size = 0;
}
}
static int radv_amdgpu_cs_find_buffer(struct radv_amdgpu_cs *cs,
amdgpu_bo_handle bo)
{
unsigned hash = ((uintptr_t)bo >> 6) & (ARRAY_SIZE(cs->buffer_hash_table) - 1);
int index = cs->buffer_hash_table[hash];
if (index == -1)
return -1;
if(cs->handles[index] == bo)
return index;
for (unsigned i = 0; i < cs->num_buffers; ++i) {
if (cs->handles[i] == bo) {
cs->buffer_hash_table[hash] = i;
return i;
}
}
return -1;
}
static void radv_amdgpu_cs_add_buffer_internal(struct radv_amdgpu_cs *cs,
amdgpu_bo_handle bo,
uint8_t priority)
{
unsigned hash;
int index = radv_amdgpu_cs_find_buffer(cs, bo);
if (index != -1) {
cs->priorities[index] = MAX2(cs->priorities[index], priority);
return;
}
if (cs->num_buffers == cs->max_num_buffers) {
unsigned new_count = MAX2(1, cs->max_num_buffers * 2);
cs->handles = realloc(cs->handles, new_count * sizeof(amdgpu_bo_handle));
cs->priorities = realloc(cs->priorities, new_count * sizeof(uint8_t));
cs->max_num_buffers = new_count;
}
cs->handles[cs->num_buffers] = bo;
cs->priorities[cs->num_buffers] = priority;
hash = ((uintptr_t)bo >> 6) & (ARRAY_SIZE(cs->buffer_hash_table) - 1);
cs->buffer_hash_table[hash] = cs->num_buffers;
++cs->num_buffers;
}
static void radv_amdgpu_cs_add_buffer(struct radeon_winsys_cs *_cs,
struct radeon_winsys_bo *_bo,
uint8_t priority)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(_cs);
struct radv_amdgpu_winsys_bo *bo = radv_amdgpu_winsys_bo(_bo);
radv_amdgpu_cs_add_buffer_internal(cs, bo->bo, priority);
}
static void radv_amdgpu_cs_execute_secondary(struct radeon_winsys_cs *_parent,
struct radeon_winsys_cs *_child)
{
struct radv_amdgpu_cs *parent = radv_amdgpu_cs(_parent);
struct radv_amdgpu_cs *child = radv_amdgpu_cs(_child);
for (unsigned i = 0; i < child->num_buffers; ++i) {
radv_amdgpu_cs_add_buffer_internal(parent, child->handles[i],
child->priorities[i]);
}
if (parent->ws->use_ib_bos) {
if (parent->base.cdw + 4 > parent->base.max_dw)
radv_amdgpu_cs_grow(&parent->base, 4);
parent->base.buf[parent->base.cdw++] = PKT3(PKT3_INDIRECT_BUFFER_CIK, 2, 0);
parent->base.buf[parent->base.cdw++] = child->ib.ib_mc_address;
parent->base.buf[parent->base.cdw++] = child->ib.ib_mc_address >> 32;
parent->base.buf[parent->base.cdw++] = child->ib.size;
} else {
if (parent->base.cdw + child->base.cdw > parent->base.max_dw)
radv_amdgpu_cs_grow(&parent->base, child->base.cdw);
memcpy(parent->base.buf + parent->base.cdw, child->base.buf, 4 * child->base.cdw);
parent->base.cdw += child->base.cdw;
}
}
static int radv_amdgpu_create_bo_list(struct radv_amdgpu_winsys *ws,
struct radeon_winsys_cs **cs_array,
unsigned count,
struct radv_amdgpu_winsys_bo *extra_bo,
amdgpu_bo_list_handle *bo_list)
{
int r;
if (ws->debug_all_bos) {
struct radv_amdgpu_winsys_bo *bo;
amdgpu_bo_handle *handles;
unsigned num = 0;
pthread_mutex_lock(&ws->global_bo_list_lock);
handles = malloc(sizeof(handles[0]) * ws->num_buffers);
if (!handles) {
pthread_mutex_unlock(&ws->global_bo_list_lock);
return -ENOMEM;
}
LIST_FOR_EACH_ENTRY(bo, &ws->global_bo_list, global_list_item) {
assert(num < ws->num_buffers);
handles[num++] = bo->bo;
}
r = amdgpu_bo_list_create(ws->dev, ws->num_buffers,
handles, NULL,
bo_list);
free(handles);
pthread_mutex_unlock(&ws->global_bo_list_lock);
} else if (count == 1 && !extra_bo) {
struct radv_amdgpu_cs *cs = (struct radv_amdgpu_cs*)cs_array[0];
r = amdgpu_bo_list_create(ws->dev, cs->num_buffers, cs->handles,
cs->priorities, bo_list);
} else {
unsigned total_buffer_count = !!extra_bo;
unsigned unique_bo_count = !!extra_bo;
for (unsigned i = 0; i < count; ++i) {
struct radv_amdgpu_cs *cs = (struct radv_amdgpu_cs*)cs_array[i];
total_buffer_count += cs->num_buffers;
}
amdgpu_bo_handle *handles = malloc(sizeof(amdgpu_bo_handle) * total_buffer_count);
uint8_t *priorities = malloc(sizeof(uint8_t) * total_buffer_count);
if (!handles || !priorities) {
free(handles);
free(priorities);
return -ENOMEM;
}
if (extra_bo) {
handles[0] = extra_bo->bo;
priorities[0] = 8;
}
for (unsigned i = 0; i < count; ++i) {
struct radv_amdgpu_cs *cs = (struct radv_amdgpu_cs*)cs_array[i];
for (unsigned j = 0; j < cs->num_buffers; ++j) {
bool found = false;
for (unsigned k = 0; k < unique_bo_count; ++k) {
if (handles[k] == cs->handles[j]) {
found = true;
priorities[k] = MAX2(priorities[k],
cs->priorities[j]);
break;
}
}
if (!found) {
handles[unique_bo_count] = cs->handles[j];
priorities[unique_bo_count] = cs->priorities[j];
++unique_bo_count;
}
}
}
r = amdgpu_bo_list_create(ws->dev, unique_bo_count, handles,
priorities, bo_list);
free(handles);
free(priorities);
}
return r;
}
static int radv_amdgpu_winsys_cs_submit_chained(struct radeon_winsys_ctx *_ctx,
struct radeon_winsys_cs **cs_array,
unsigned cs_count,
struct radeon_winsys_fence *_fence)
{
int r;
struct radv_amdgpu_ctx *ctx = radv_amdgpu_ctx(_ctx);
struct amdgpu_cs_fence *fence = (struct amdgpu_cs_fence *)_fence;
struct radv_amdgpu_cs *cs0 = radv_amdgpu_cs(cs_array[0]);
amdgpu_bo_list_handle bo_list;
struct amdgpu_cs_request request = {0};
for (unsigned i = cs_count; i--;) {
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(cs_array[i]);
if (cs->is_chained) {
*cs->ib_size_ptr -= 4;
cs->is_chained = false;
}
if (i + 1 < cs_count) {
struct radv_amdgpu_cs *next = radv_amdgpu_cs(cs_array[i + 1]);
assert(cs->base.cdw + 4 <= cs->base.max_dw);
cs->is_chained = true;
*cs->ib_size_ptr += 4;
cs->base.buf[cs->base.cdw + 0] = PKT3(PKT3_INDIRECT_BUFFER_CIK, 2, 0);
cs->base.buf[cs->base.cdw + 1] = next->ib.ib_mc_address;
cs->base.buf[cs->base.cdw + 2] = next->ib.ib_mc_address >> 32;
cs->base.buf[cs->base.cdw + 3] = S_3F2_CHAIN(1) | S_3F2_VALID(1) | next->ib.size;
}
}
r = radv_amdgpu_create_bo_list(cs0->ws, cs_array, cs_count, NULL, &bo_list);
if (r) {
fprintf(stderr, "amdgpu: Failed to created the BO list for submission\n");
return r;
}
request.ip_type = AMDGPU_HW_IP_GFX;
request.number_of_ibs = 1;
request.ibs = &cs0->ib;
request.resources = bo_list;
r = amdgpu_cs_submit(ctx->ctx, 0, &request, 1);
if (r) {
if (r == -ENOMEM)
fprintf(stderr, "amdgpu: Not enough memory for command submission.\n");
else
fprintf(stderr, "amdgpu: The CS has been rejected, "
"see dmesg for more information.\n");
}
amdgpu_bo_list_destroy(bo_list);
if (fence) {
fence->context = ctx->ctx;
fence->ip_type = request.ip_type;
fence->ip_instance = request.ip_instance;
fence->ring = request.ring;
fence->fence = request.seq_no;
}
ctx->last_seq_no = request.seq_no;
return r;
}
static int radv_amdgpu_winsys_cs_submit_fallback(struct radeon_winsys_ctx *_ctx,
struct radeon_winsys_cs **cs_array,
unsigned cs_count,
struct radeon_winsys_fence *_fence)
{
int r;
struct radv_amdgpu_ctx *ctx = radv_amdgpu_ctx(_ctx);
struct amdgpu_cs_fence *fence = (struct amdgpu_cs_fence *)_fence;
amdgpu_bo_list_handle bo_list;
struct amdgpu_cs_request request;
assert(cs_count);
for (unsigned i = 0; i < cs_count;) {
struct radv_amdgpu_cs *cs0 = radv_amdgpu_cs(cs_array[i]);
struct amdgpu_cs_ib_info ibs[AMDGPU_CS_MAX_IBS_PER_SUBMIT];
unsigned cnt = MIN2(AMDGPU_CS_MAX_IBS_PER_SUBMIT, cs_count - i);
memset(&request, 0, sizeof(request));
r = radv_amdgpu_create_bo_list(cs0->ws, &cs_array[i], cnt, NULL, &bo_list);
if (r) {
fprintf(stderr, "amdgpu: Failed to created the BO list for submission\n");
return r;
}
request.ip_type = AMDGPU_HW_IP_GFX;
request.resources = bo_list;
request.number_of_ibs = cnt;
request.ibs = ibs;
for (unsigned j = 0; j < cnt; ++j) {
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(cs_array[i + j]);
ibs[j] = cs->ib;
if (cs->is_chained) {
*cs->ib_size_ptr -= 4;
cs->is_chained = false;
}
}
r = amdgpu_cs_submit(ctx->ctx, 0, &request, 1);
if (r) {
if (r == -ENOMEM)
fprintf(stderr, "amdgpu: Not enough memory for command submission.\n");
else
fprintf(stderr, "amdgpu: The CS has been rejected, "
"see dmesg for more information.\n");
}
amdgpu_bo_list_destroy(bo_list);
if (r)
return r;
i += cnt;
}
if (fence) {
fence->context = ctx->ctx;
fence->ip_type = request.ip_type;
fence->ip_instance = request.ip_instance;
fence->ring = request.ring;
fence->fence = request.seq_no;
}
ctx->last_seq_no = request.seq_no;
return 0;
}
static int radv_amdgpu_winsys_cs_submit_sysmem(struct radeon_winsys_ctx *_ctx,
struct radeon_winsys_cs **cs_array,
unsigned cs_count,
struct radeon_winsys_fence *_fence)
{
int r;
struct radv_amdgpu_ctx *ctx = radv_amdgpu_ctx(_ctx);
struct amdgpu_cs_fence *fence = (struct amdgpu_cs_fence *)_fence;
struct radv_amdgpu_cs *cs0 = radv_amdgpu_cs(cs_array[0]);
struct radeon_winsys *ws = (struct radeon_winsys*)cs0->ws;
amdgpu_bo_list_handle bo_list;
struct amdgpu_cs_request request;
uint32_t pad_word = 0xffff1000U;
if (radv_amdgpu_winsys(ws)->family == FAMILY_SI)
pad_word = 0x80000000;
assert(cs_count);
for (unsigned i = 0; i < cs_count;) {
struct amdgpu_cs_ib_info ib = {0};
struct radeon_winsys_bo *bo = NULL;
uint32_t *ptr;
unsigned cnt = 0;
unsigned size = 0;
while (i + cnt < cs_count && 0xffff8 - size >= radv_amdgpu_cs(cs_array[i + cnt])->base.cdw) {
size += radv_amdgpu_cs(cs_array[i + cnt])->base.cdw;
++cnt;
}
assert(cnt);
bo = ws->buffer_create(ws, 4 * size, 4096, RADEON_DOMAIN_GTT, RADEON_FLAG_CPU_ACCESS);
ptr = ws->buffer_map(bo);
for (unsigned j = 0; j < cnt; ++j) {
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(cs_array[i + j]);
memcpy(ptr, cs->base.buf, 4 * cs->base.cdw);
ptr += cs->base.cdw;
}
while(!size || (size & 7)) {
*ptr++ = pad_word;
++size;
}
memset(&request, 0, sizeof(request));
r = radv_amdgpu_create_bo_list(cs0->ws, &cs_array[i], cnt,
(struct radv_amdgpu_winsys_bo*)bo, &bo_list);
if (r) {
fprintf(stderr, "amdgpu: Failed to created the BO list for submission\n");
return r;
}
ib.size = size;
ib.ib_mc_address = ws->buffer_get_va(bo);
request.ip_type = AMDGPU_HW_IP_GFX;
request.resources = bo_list;
request.number_of_ibs = 1;
request.ibs = &ib;
r = amdgpu_cs_submit(ctx->ctx, 0, &request, 1);
if (r) {
if (r == -ENOMEM)
fprintf(stderr, "amdgpu: Not enough memory for command submission.\n");
else
fprintf(stderr, "amdgpu: The CS has been rejected, "
"see dmesg for more information.\n");
}
amdgpu_bo_list_destroy(bo_list);
ws->buffer_destroy(bo);
if (r)
return r;
i += cnt;
}
if (fence) {
fence->context = ctx->ctx;
fence->ip_type = request.ip_type;
fence->ip_instance = request.ip_instance;
fence->ring = request.ring;
fence->fence = request.seq_no;
}
ctx->last_seq_no = request.seq_no;
return 0;
}
static int radv_amdgpu_winsys_cs_submit(struct radeon_winsys_ctx *_ctx,
struct radeon_winsys_cs **cs_array,
unsigned cs_count,
bool can_patch,
struct radeon_winsys_fence *_fence)
{
struct radv_amdgpu_cs *cs = radv_amdgpu_cs(cs_array[0]);
if (!cs->ws->use_ib_bos) {
return radv_amdgpu_winsys_cs_submit_sysmem(_ctx, cs_array,
cs_count, _fence);
} else if (can_patch && cs_count > AMDGPU_CS_MAX_IBS_PER_SUBMIT && false) {
return radv_amdgpu_winsys_cs_submit_chained(_ctx, cs_array,
cs_count, _fence);
} else {
return radv_amdgpu_winsys_cs_submit_fallback(_ctx, cs_array,
cs_count, _fence);
}
}
static struct radeon_winsys_ctx *radv_amdgpu_ctx_create(struct radeon_winsys *_ws)
{
struct radv_amdgpu_winsys *ws = radv_amdgpu_winsys(_ws);
struct radv_amdgpu_ctx *ctx = CALLOC_STRUCT(radv_amdgpu_ctx);
int r;
if (!ctx)
return NULL;
r = amdgpu_cs_ctx_create(ws->dev, &ctx->ctx);
if (r) {
fprintf(stderr, "amdgpu: radv_amdgpu_cs_ctx_create failed. (%i)\n", r);
goto error_create;
}
ctx->ws = ws;
return (struct radeon_winsys_ctx *)ctx;
error_create:
return NULL;
}
static void radv_amdgpu_ctx_destroy(struct radeon_winsys_ctx *rwctx)
{
struct radv_amdgpu_ctx *ctx = (struct radv_amdgpu_ctx *)rwctx;
amdgpu_cs_ctx_free(ctx->ctx);
FREE(ctx);
}
static bool radv_amdgpu_ctx_wait_idle(struct radeon_winsys_ctx *rwctx)
{
struct radv_amdgpu_ctx *ctx = (struct radv_amdgpu_ctx *)rwctx;
if (ctx->last_seq_no) {
uint32_t expired;
struct amdgpu_cs_fence fence;
fence.context = ctx->ctx;
fence.ip_type = RING_GFX;
fence.ip_instance = 0;
fence.ring = 0;
fence.fence = ctx->last_seq_no;
int ret = amdgpu_cs_query_fence_status(&fence, 1000000000ull, 0,
&expired);
if (ret || !expired)
return false;
}
return true;
}
void radv_amdgpu_cs_init_functions(struct radv_amdgpu_winsys *ws)
{
ws->base.ctx_create = radv_amdgpu_ctx_create;
ws->base.ctx_destroy = radv_amdgpu_ctx_destroy;
ws->base.ctx_wait_idle = radv_amdgpu_ctx_wait_idle;
ws->base.cs_create = radv_amdgpu_cs_create;
ws->base.cs_destroy = radv_amdgpu_cs_destroy;
ws->base.cs_grow = radv_amdgpu_cs_grow;
ws->base.cs_finalize = radv_amdgpu_cs_finalize;
ws->base.cs_reset = radv_amdgpu_cs_reset;
ws->base.cs_add_buffer = radv_amdgpu_cs_add_buffer;
ws->base.cs_execute_secondary = radv_amdgpu_cs_execute_secondary;
ws->base.cs_submit = radv_amdgpu_winsys_cs_submit;
ws->base.create_fence = radv_amdgpu_create_fence;
ws->base.destroy_fence = radv_amdgpu_destroy_fence;
ws->base.fence_wait = radv_amdgpu_fence_wait;
}

View File

@ -0,0 +1,51 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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.
*/
#pragma once
#include <string.h>
#include <stdint.h>
#include <assert.h>
#include "r600d_common.h"
#include <amdgpu.h>
#include "radv_radeon_winsys.h"
#include "radv_amdgpu_winsys.h"
struct radv_amdgpu_ctx {
struct radv_amdgpu_winsys *ws;
amdgpu_context_handle ctx;
uint64_t last_seq_no;
};
static inline struct radv_amdgpu_ctx *
radv_amdgpu_ctx(struct radeon_winsys_ctx *base)
{
return (struct radv_amdgpu_ctx *)base;
}
void radv_amdgpu_cs_init_functions(struct radv_amdgpu_winsys *ws);

View File

@ -0,0 +1,523 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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 <errno.h>
#include "radv_private.h"
#include "addrlib/addrinterface.h"
#include "util/bitset.h"
#include "radv_amdgpu_winsys.h"
#include "radv_amdgpu_surface.h"
#include "sid.h"
#ifndef NO_ENTRIES
#define NO_ENTRIES 32
#endif
#ifndef NO_MACRO_ENTRIES
#define NO_MACRO_ENTRIES 16
#endif
#ifndef CIASICIDGFXENGINE_SOUTHERNISLAND
#define CIASICIDGFXENGINE_SOUTHERNISLAND 0x0000000A
#endif
static int radv_amdgpu_surface_sanity(const struct radeon_surf *surf)
{
unsigned type = RADEON_SURF_GET(surf->flags, TYPE);
if (!(surf->flags & RADEON_SURF_HAS_TILE_MODE_INDEX))
return -EINVAL;
/* all dimension must be at least 1 ! */
if (!surf->npix_x || !surf->npix_y || !surf->npix_z ||
!surf->array_size)
return -EINVAL;
if (!surf->blk_w || !surf->blk_h || !surf->blk_d)
return -EINVAL;
switch (surf->nsamples) {
case 1:
case 2:
case 4:
case 8:
break;
default:
return -EINVAL;
}
switch (type) {
case RADEON_SURF_TYPE_1D:
if (surf->npix_y > 1)
return -EINVAL;
/* fall through */
case RADEON_SURF_TYPE_2D:
case RADEON_SURF_TYPE_CUBEMAP:
if (surf->npix_z > 1 || surf->array_size > 1)
return -EINVAL;
break;
case RADEON_SURF_TYPE_3D:
if (surf->array_size > 1)
return -EINVAL;
break;
case RADEON_SURF_TYPE_1D_ARRAY:
if (surf->npix_y > 1)
return -EINVAL;
/* fall through */
case RADEON_SURF_TYPE_2D_ARRAY:
if (surf->npix_z > 1)
return -EINVAL;
break;
default:
return -EINVAL;
}
return 0;
}
static void *ADDR_API radv_allocSysMem(const ADDR_ALLOCSYSMEM_INPUT * pInput)
{
return malloc(pInput->sizeInBytes);
}
static ADDR_E_RETURNCODE ADDR_API radv_freeSysMem(const ADDR_FREESYSMEM_INPUT * pInput)
{
free(pInput->pVirtAddr);
return ADDR_OK;
}
ADDR_HANDLE radv_amdgpu_addr_create(struct amdgpu_gpu_info *amdinfo, int family, int rev_id,
enum chip_class chip_class)
{
ADDR_CREATE_INPUT addrCreateInput = {0};
ADDR_CREATE_OUTPUT addrCreateOutput = {0};
ADDR_REGISTER_VALUE regValue = {0};
ADDR_CREATE_FLAGS createFlags = {{0}};
ADDR_E_RETURNCODE addrRet;
addrCreateInput.size = sizeof(ADDR_CREATE_INPUT);
addrCreateOutput.size = sizeof(ADDR_CREATE_OUTPUT);
regValue.noOfBanks = amdinfo->mc_arb_ramcfg & 0x3;
regValue.gbAddrConfig = amdinfo->gb_addr_cfg;
regValue.noOfRanks = (amdinfo->mc_arb_ramcfg & 0x4) >> 2;
regValue.backendDisables = amdinfo->backend_disable[0];
regValue.pTileConfig = amdinfo->gb_tile_mode;
regValue.noOfEntries = ARRAY_SIZE(amdinfo->gb_tile_mode);
if (chip_class == SI) {
regValue.pMacroTileConfig = NULL;
regValue.noOfMacroEntries = 0;
} else {
regValue.pMacroTileConfig = amdinfo->gb_macro_tile_mode;
regValue.noOfMacroEntries = ARRAY_SIZE(amdinfo->gb_macro_tile_mode);
}
createFlags.value = 0;
createFlags.useTileIndex = 1;
createFlags.degradeBaseLevel = 1;
addrCreateInput.chipEngine = CIASICIDGFXENGINE_SOUTHERNISLAND;
addrCreateInput.chipFamily = family;
addrCreateInput.chipRevision = rev_id;
addrCreateInput.createFlags = createFlags;
addrCreateInput.callbacks.allocSysMem = radv_allocSysMem;
addrCreateInput.callbacks.freeSysMem = radv_freeSysMem;
addrCreateInput.callbacks.debugPrint = 0;
addrCreateInput.regValue = regValue;
addrRet = AddrCreate(&addrCreateInput, &addrCreateOutput);
if (addrRet != ADDR_OK)
return NULL;
return addrCreateOutput.hLib;
}
static int radv_compute_level(ADDR_HANDLE addrlib,
struct radeon_surf *surf, bool is_stencil,
unsigned level, unsigned type, bool compressed,
ADDR_COMPUTE_SURFACE_INFO_INPUT *AddrSurfInfoIn,
ADDR_COMPUTE_SURFACE_INFO_OUTPUT *AddrSurfInfoOut,
ADDR_COMPUTE_DCCINFO_INPUT *AddrDccIn,
ADDR_COMPUTE_DCCINFO_OUTPUT *AddrDccOut)
{
struct radeon_surf_level *surf_level;
ADDR_E_RETURNCODE ret;
AddrSurfInfoIn->mipLevel = level;
AddrSurfInfoIn->width = u_minify(surf->npix_x, level);
AddrSurfInfoIn->height = u_minify(surf->npix_y, level);
if (type == RADEON_SURF_TYPE_3D)
AddrSurfInfoIn->numSlices = u_minify(surf->npix_z, level);
else if (type == RADEON_SURF_TYPE_CUBEMAP)
AddrSurfInfoIn->numSlices = 6;
else
AddrSurfInfoIn->numSlices = surf->array_size;
if (level > 0) {
/* Set the base level pitch. This is needed for calculation
* of non-zero levels. */
if (is_stencil)
AddrSurfInfoIn->basePitch = surf->stencil_level[0].nblk_x;
else
AddrSurfInfoIn->basePitch = surf->level[0].nblk_x;
/* Convert blocks to pixels for compressed formats. */
if (compressed)
AddrSurfInfoIn->basePitch *= surf->blk_w;
}
ret = AddrComputeSurfaceInfo(addrlib,
AddrSurfInfoIn,
AddrSurfInfoOut);
if (ret != ADDR_OK) {
return ret;
}
surf_level = is_stencil ? &surf->stencil_level[level] : &surf->level[level];
surf_level->offset = align64(surf->bo_size, AddrSurfInfoOut->baseAlign);
surf_level->slice_size = AddrSurfInfoOut->sliceSize;
surf_level->pitch_bytes = AddrSurfInfoOut->pitch * (is_stencil ? 1 : surf->bpe);
surf_level->npix_x = u_minify(surf->npix_x, level);
surf_level->npix_y = u_minify(surf->npix_y, level);
surf_level->npix_z = u_minify(surf->npix_z, level);
surf_level->nblk_x = AddrSurfInfoOut->pitch;
surf_level->nblk_y = AddrSurfInfoOut->height;
if (type == RADEON_SURF_TYPE_3D)
surf_level->nblk_z = AddrSurfInfoOut->depth;
else
surf_level->nblk_z = 1;
switch (AddrSurfInfoOut->tileMode) {
case ADDR_TM_LINEAR_ALIGNED:
surf_level->mode = RADEON_SURF_MODE_LINEAR_ALIGNED;
break;
case ADDR_TM_1D_TILED_THIN1:
surf_level->mode = RADEON_SURF_MODE_1D;
break;
case ADDR_TM_2D_TILED_THIN1:
surf_level->mode = RADEON_SURF_MODE_2D;
break;
default:
assert(0);
}
if (is_stencil)
surf->stencil_tiling_index[level] = AddrSurfInfoOut->tileIndex;
else
surf->tiling_index[level] = AddrSurfInfoOut->tileIndex;
surf->bo_size = surf_level->offset + AddrSurfInfoOut->surfSize;
/* Clear DCC fields at the beginning. */
surf_level->dcc_offset = 0;
surf_level->dcc_enabled = false;
/* The previous level's flag tells us if we can use DCC for this level. */
if (AddrSurfInfoIn->flags.dccCompatible &&
(level == 0 || AddrDccOut->subLvlCompressible)) {
AddrDccIn->colorSurfSize = AddrSurfInfoOut->surfSize;
AddrDccIn->tileMode = AddrSurfInfoOut->tileMode;
AddrDccIn->tileInfo = *AddrSurfInfoOut->pTileInfo;
AddrDccIn->tileIndex = AddrSurfInfoOut->tileIndex;
AddrDccIn->macroModeIndex = AddrSurfInfoOut->macroModeIndex;
ret = AddrComputeDccInfo(addrlib,
AddrDccIn,
AddrDccOut);
if (ret == ADDR_OK) {
surf_level->dcc_offset = surf->dcc_size;
surf_level->dcc_fast_clear_size = AddrDccOut->dccFastClearSize;
surf_level->dcc_enabled = true;
surf->dcc_size = surf_level->dcc_offset + AddrDccOut->dccRamSize;
surf->dcc_alignment = MAX(surf->dcc_alignment, AddrDccOut->dccRamBaseAlign);
}
}
return 0;
}
static void radv_set_micro_tile_mode(struct radeon_surf *surf,
struct radeon_info *info)
{
uint32_t tile_mode = info->si_tile_mode_array[surf->tiling_index[0]];
if (info->chip_class >= CIK)
surf->micro_tile_mode = G_009910_MICRO_TILE_MODE_NEW(tile_mode);
else
surf->micro_tile_mode = G_009910_MICRO_TILE_MODE(tile_mode);
}
static int radv_amdgpu_winsys_surface_init(struct radeon_winsys *_ws,
struct radeon_surf *surf)
{
struct radv_amdgpu_winsys *ws = radv_amdgpu_winsys(_ws);
unsigned level, mode, type;
bool compressed;
ADDR_COMPUTE_SURFACE_INFO_INPUT AddrSurfInfoIn = {0};
ADDR_COMPUTE_SURFACE_INFO_OUTPUT AddrSurfInfoOut = {0};
ADDR_COMPUTE_DCCINFO_INPUT AddrDccIn = {0};
ADDR_COMPUTE_DCCINFO_OUTPUT AddrDccOut = {0};
ADDR_TILEINFO AddrTileInfoIn = {0};
ADDR_TILEINFO AddrTileInfoOut = {0};
int r;
r = radv_amdgpu_surface_sanity(surf);
if (r)
return r;
AddrSurfInfoIn.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_INPUT);
AddrSurfInfoOut.size = sizeof(ADDR_COMPUTE_SURFACE_INFO_OUTPUT);
AddrDccIn.size = sizeof(ADDR_COMPUTE_DCCINFO_INPUT);
AddrDccOut.size = sizeof(ADDR_COMPUTE_DCCINFO_OUTPUT);
AddrSurfInfoOut.pTileInfo = &AddrTileInfoOut;
type = RADEON_SURF_GET(surf->flags, TYPE);
mode = RADEON_SURF_GET(surf->flags, MODE);
compressed = surf->blk_w == 4 && surf->blk_h == 4;
/* MSAA and FMASK require 2D tiling. */
if (surf->nsamples > 1 ||
(surf->flags & RADEON_SURF_FMASK))
mode = RADEON_SURF_MODE_2D;
/* DB doesn't support linear layouts. */
if (surf->flags & (RADEON_SURF_Z_OR_SBUFFER) &&
mode < RADEON_SURF_MODE_1D)
mode = RADEON_SURF_MODE_1D;
/* Set the requested tiling mode. */
switch (mode) {
case RADEON_SURF_MODE_LINEAR_ALIGNED:
AddrSurfInfoIn.tileMode = ADDR_TM_LINEAR_ALIGNED;
break;
case RADEON_SURF_MODE_1D:
AddrSurfInfoIn.tileMode = ADDR_TM_1D_TILED_THIN1;
break;
case RADEON_SURF_MODE_2D:
AddrSurfInfoIn.tileMode = ADDR_TM_2D_TILED_THIN1;
break;
default:
assert(0);
}
/* The format must be set correctly for the allocation of compressed
* textures to work. In other cases, setting the bpp is sufficient. */
if (compressed) {
switch (surf->bpe) {
case 8:
AddrSurfInfoIn.format = ADDR_FMT_BC1;
break;
case 16:
AddrSurfInfoIn.format = ADDR_FMT_BC3;
break;
default:
assert(0);
}
}
else {
AddrDccIn.bpp = AddrSurfInfoIn.bpp = surf->bpe * 8;
}
AddrDccIn.numSamples = AddrSurfInfoIn.numSamples = surf->nsamples;
AddrSurfInfoIn.tileIndex = -1;
/* Set the micro tile type. */
if (surf->flags & RADEON_SURF_SCANOUT)
AddrSurfInfoIn.tileType = ADDR_DISPLAYABLE;
else if (surf->flags & RADEON_SURF_Z_OR_SBUFFER)
AddrSurfInfoIn.tileType = ADDR_DEPTH_SAMPLE_ORDER;
else
AddrSurfInfoIn.tileType = ADDR_NON_DISPLAYABLE;
AddrSurfInfoIn.flags.color = !(surf->flags & RADEON_SURF_Z_OR_SBUFFER);
AddrSurfInfoIn.flags.depth = (surf->flags & RADEON_SURF_ZBUFFER) != 0;
AddrSurfInfoIn.flags.cube = type == RADEON_SURF_TYPE_CUBEMAP;
AddrSurfInfoIn.flags.display = (surf->flags & RADEON_SURF_SCANOUT) != 0;
AddrSurfInfoIn.flags.pow2Pad = surf->last_level > 0;
AddrSurfInfoIn.flags.degrade4Space = 1;
/* DCC notes:
* - If we add MSAA support, keep in mind that CB can't decompress 8bpp
* with samples >= 4.
* - Mipmapped array textures have low performance (discovered by a closed
* driver team).
*/
AddrSurfInfoIn.flags.dccCompatible = !(surf->flags & RADEON_SURF_Z_OR_SBUFFER) &&
!(surf->flags & RADEON_SURF_DISABLE_DCC) &&
!compressed && AddrDccIn.numSamples <= 1 &&
((surf->array_size == 1 && surf->npix_z == 1) ||
surf->last_level == 0);
AddrSurfInfoIn.flags.noStencil = (surf->flags & RADEON_SURF_SBUFFER) == 0;
AddrSurfInfoIn.flags.compressZ = AddrSurfInfoIn.flags.depth;
/* noStencil = 0 can result in a depth part that is incompatible with
* mipmapped texturing. So set noStencil = 1 when mipmaps are requested (in
* this case, we may end up setting stencil_adjusted).
*
* TODO: update addrlib to a newer version, remove this, and
* use flags.matchStencilTileCfg = 1 as an alternative fix.
*/
if (surf->last_level > 0)
AddrSurfInfoIn.flags.noStencil = 1;
/* Set preferred macrotile parameters. This is usually required
* for shared resources. This is for 2D tiling only. */
if (AddrSurfInfoIn.tileMode >= ADDR_TM_2D_TILED_THIN1 &&
surf->bankw && surf->bankh && surf->mtilea && surf->tile_split) {
/* If any of these parameters are incorrect, the calculation
* will fail. */
AddrTileInfoIn.banks = surf->num_banks;
AddrTileInfoIn.bankWidth = surf->bankw;
AddrTileInfoIn.bankHeight = surf->bankh;
AddrTileInfoIn.macroAspectRatio = surf->mtilea;
AddrTileInfoIn.tileSplitBytes = surf->tile_split;
AddrTileInfoIn.pipeConfig = surf->pipe_config + 1; /* +1 compared to GB_TILE_MODE */
AddrSurfInfoIn.flags.degrade4Space = 0;
AddrSurfInfoIn.pTileInfo = &AddrTileInfoIn;
/* If AddrSurfInfoIn.pTileInfo is set, Addrlib doesn't set
* the tile index, because we are expected to know it if
* we know the other parameters.
*
* This is something that can easily be fixed in Addrlib.
* For now, just figure it out here.
* Note that only 2D_TILE_THIN1 is handled here.
*/
assert(!(surf->flags & RADEON_SURF_Z_OR_SBUFFER));
assert(AddrSurfInfoIn.tileMode == ADDR_TM_2D_TILED_THIN1);
if (ws->info.chip_class == SI) {
if (AddrSurfInfoIn.tileType == ADDR_DISPLAYABLE) {
if (surf->bpe == 2)
AddrSurfInfoIn.tileIndex = 11; /* 16bpp */
else
AddrSurfInfoIn.tileIndex = 12; /* 32bpp */
} else {
if (surf->bpe == 1)
AddrSurfInfoIn.tileIndex = 14; /* 8bpp */
else if (surf->bpe == 2)
AddrSurfInfoIn.tileIndex = 15; /* 16bpp */
else if (surf->bpe == 4)
AddrSurfInfoIn.tileIndex = 16; /* 32bpp */
else
AddrSurfInfoIn.tileIndex = 17; /* 64bpp (and 128bpp) */
}
} else {
if (AddrSurfInfoIn.tileType == ADDR_DISPLAYABLE)
AddrSurfInfoIn.tileIndex = 10; /* 2D displayable */
else
AddrSurfInfoIn.tileIndex = 14; /* 2D non-displayable */
}
}
surf->bo_size = 0;
surf->dcc_size = 0;
surf->dcc_alignment = 1;
/* Calculate texture layout information. */
for (level = 0; level <= surf->last_level; level++) {
r = radv_compute_level(ws->addrlib, surf, false, level, type, compressed,
&AddrSurfInfoIn, &AddrSurfInfoOut, &AddrDccIn, &AddrDccOut);
if (r)
return r;
if (level == 0) {
surf->bo_alignment = AddrSurfInfoOut.baseAlign;
surf->pipe_config = AddrSurfInfoOut.pTileInfo->pipeConfig - 1;
radv_set_micro_tile_mode(surf, &ws->info);
/* For 2D modes only. */
if (AddrSurfInfoOut.tileMode >= ADDR_TM_2D_TILED_THIN1) {
surf->bankw = AddrSurfInfoOut.pTileInfo->bankWidth;
surf->bankh = AddrSurfInfoOut.pTileInfo->bankHeight;
surf->mtilea = AddrSurfInfoOut.pTileInfo->macroAspectRatio;
surf->tile_split = AddrSurfInfoOut.pTileInfo->tileSplitBytes;
surf->num_banks = AddrSurfInfoOut.pTileInfo->banks;
surf->macro_tile_index = AddrSurfInfoOut.macroModeIndex;
} else {
surf->macro_tile_index = 0;
}
}
}
/* Calculate texture layout information for stencil. */
if (surf->flags & RADEON_SURF_SBUFFER) {
AddrSurfInfoIn.bpp = 8;
AddrSurfInfoIn.flags.depth = 0;
AddrSurfInfoIn.flags.stencil = 1;
/* This will be ignored if AddrSurfInfoIn.pTileInfo is NULL. */
AddrTileInfoIn.tileSplitBytes = surf->stencil_tile_split;
for (level = 0; level <= surf->last_level; level++) {
r = radv_compute_level(ws->addrlib, surf, true, level, type, compressed,
&AddrSurfInfoIn, &AddrSurfInfoOut, &AddrDccIn, &AddrDccOut);
if (r)
return r;
/* DB uses the depth pitch for both stencil and depth. */
if (surf->stencil_level[level].nblk_x != surf->level[level].nblk_x)
surf->stencil_adjusted = true;
if (level == 0) {
/* For 2D modes only. */
if (AddrSurfInfoOut.tileMode >= ADDR_TM_2D_TILED_THIN1) {
surf->stencil_tile_split =
AddrSurfInfoOut.pTileInfo->tileSplitBytes;
}
}
}
}
/* Recalculate the whole DCC miptree size including disabled levels.
* This is what addrlib does, but calling addrlib would be a lot more
* complicated.
*/
#if 0
if (surf->dcc_size && surf->last_level > 0) {
surf->dcc_size = align64(surf->bo_size >> 8,
ws->info.pipe_interleave_bytes *
ws->info.num_tile_pipes);
}
#endif
return 0;
}
static int radv_amdgpu_winsys_surface_best(struct radeon_winsys *rws,
struct radeon_surf *surf)
{
return 0;
}
void radv_amdgpu_surface_init_functions(struct radv_amdgpu_winsys *ws)
{
ws->base.surface_init = radv_amdgpu_winsys_surface_init;
ws->base.surface_best = radv_amdgpu_winsys_surface_best;
}

View File

@ -0,0 +1,29 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* 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.
*/
#pragma once
#include <amdgpu.h>
void radv_amdgpu_surface_init_functions(struct radv_amdgpu_winsys *ws);
ADDR_HANDLE radv_amdgpu_addr_create(struct amdgpu_gpu_info *amdinfo, int family, int rev_id, enum chip_class chip_class);

View File

@ -0,0 +1,359 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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 "radv_amdgpu_winsys.h"
#include "radv_amdgpu_winsys_public.h"
#include "radv_amdgpu_surface.h"
#include "amdgpu_id.h"
#include "xf86drm.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <amdgpu_drm.h>
#include <assert.h>
#include "radv_amdgpu_cs.h"
#include "radv_amdgpu_bo.h"
#include "radv_amdgpu_surface.h"
#define CIK_TILE_MODE_COLOR_2D 14
#define CIK__GB_TILE_MODE__PIPE_CONFIG(x) (((x) >> 6) & 0x1f)
#define CIK__PIPE_CONFIG__ADDR_SURF_P2 0
#define CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16 4
#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16 5
#define CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32 6
#define CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32 7
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16 8
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16 9
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16 10
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16 11
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16 12
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32 13
#define CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32 14
#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16 16
#define CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16 17
static unsigned radv_cik_get_num_tile_pipes(struct amdgpu_gpu_info *info)
{
unsigned mode2d = info->gb_tile_mode[CIK_TILE_MODE_COLOR_2D];
switch (CIK__GB_TILE_MODE__PIPE_CONFIG(mode2d)) {
case CIK__PIPE_CONFIG__ADDR_SURF_P2:
return 2;
case CIK__PIPE_CONFIG__ADDR_SURF_P4_8x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P4_16x32:
case CIK__PIPE_CONFIG__ADDR_SURF_P4_32x32:
return 4;
case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x16_8x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_8x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_8x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_16x32_16x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x16:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x32_16x32:
case CIK__PIPE_CONFIG__ADDR_SURF_P8_32x64_32x32:
return 8;
case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_8X16:
case CIK__PIPE_CONFIG__ADDR_SURF_P16_32X32_16X16:
return 16;
default:
fprintf(stderr, "Invalid CIK pipe configuration, assuming P2\n");
assert(!"this should never occur");
return 2;
}
}
static const char *
get_chip_name(enum radeon_family family)
{
switch (family) {
case CHIP_TAHITI: return "AMD RADV TAHITI";
case CHIP_PITCAIRN: return "AMD RADV PITCAIRN";
case CHIP_VERDE: return "AMD RADV CAPE VERDE";
case CHIP_OLAND: return "AMD RADV OLAND";
case CHIP_HAINAN: return "AMD RADV HAINAN";
case CHIP_BONAIRE: return "AMD RADV BONAIRE";
case CHIP_KAVERI: return "AMD RADV KAVERI";
case CHIP_KABINI: return "AMD RADV KABINI";
case CHIP_HAWAII: return "AMD RADV HAWAII";
case CHIP_MULLINS: return "AMD RADV MULLINS";
case CHIP_TONGA: return "AMD RADV TONGA";
case CHIP_ICELAND: return "AMD RADV ICELAND";
case CHIP_CARRIZO: return "AMD RADV CARRIZO";
case CHIP_FIJI: return "AMD RADV FIJI";
case CHIP_POLARIS10: return "AMD RADV POLARIS10";
case CHIP_POLARIS11: return "AMD RADV POLARIS11";
case CHIP_STONEY: return "AMD RADV STONEY";
default: return "AMD RADV unknown";
}
}
static bool
do_winsys_init(struct radv_amdgpu_winsys *ws, int fd)
{
struct amdgpu_buffer_size_alignments alignment_info = {};
struct amdgpu_heap_info vram, gtt;
struct drm_amdgpu_info_hw_ip dma = {};
drmDevicePtr devinfo;
int r;
int i, j;
/* Get PCI info. */
r = drmGetDevice(fd, &devinfo);
if (r) {
fprintf(stderr, "amdgpu: drmGetDevice failed.\n");
goto fail;
}
ws->info.pci_domain = devinfo->businfo.pci->domain;
ws->info.pci_bus = devinfo->businfo.pci->bus;
ws->info.pci_dev = devinfo->businfo.pci->dev;
ws->info.pci_func = devinfo->businfo.pci->func;
drmFreeDevice(&devinfo);
/* Query hardware and driver information. */
r = amdgpu_query_gpu_info(ws->dev, &ws->amdinfo);
if (r) {
fprintf(stderr, "amdgpu: amdgpu_query_gpu_info failed.\n");
goto fail;
}
r = amdgpu_query_buffer_size_alignment(ws->dev, &alignment_info);
if (r) {
fprintf(stderr, "amdgpu: amdgpu_query_buffer_size_alignment failed.\n");
goto fail;
}
r = amdgpu_query_heap_info(ws->dev, AMDGPU_GEM_DOMAIN_VRAM, 0, &vram);
if (r) {
fprintf(stderr, "amdgpu: amdgpu_query_heap_info(vram) failed.\n");
goto fail;
}
r = amdgpu_query_heap_info(ws->dev, AMDGPU_GEM_DOMAIN_GTT, 0, &gtt);
if (r) {
fprintf(stderr, "amdgpu: amdgpu_query_heap_info(gtt) failed.\n");
goto fail;
}
r = amdgpu_query_hw_ip_info(ws->dev, AMDGPU_HW_IP_DMA, 0, &dma);
if (r) {
fprintf(stderr, "amdgpu: amdgpu_query_hw_ip_info(dma) failed.\n");
goto fail;
}
ws->info.pci_id = ws->amdinfo.asic_id; /* TODO: is this correct? */
ws->info.vce_harvest_config = ws->amdinfo.vce_harvest_config;
switch (ws->info.pci_id) {
#define CHIPSET(pci_id, name, cfamily) case pci_id: ws->info.family = CHIP_##cfamily; break;
#include "pci_ids/radeonsi_pci_ids.h"
#undef CHIPSET
default:
fprintf(stderr, "amdgpu: Invalid PCI ID.\n");
goto fail;
}
if (ws->info.family >= CHIP_TONGA)
ws->info.chip_class = VI;
else if (ws->info.family >= CHIP_BONAIRE)
ws->info.chip_class = CIK;
else if (ws->info.family >= CHIP_TAHITI)
ws->info.chip_class = SI;
else {
fprintf(stderr, "amdgpu: Unknown family.\n");
goto fail;
}
/* family and rev_id are for addrlib */
switch (ws->info.family) {
case CHIP_TAHITI:
ws->family = FAMILY_SI;
ws->rev_id = SI_TAHITI_P_A0;
break;
case CHIP_PITCAIRN:
ws->family = FAMILY_SI;
ws->rev_id = SI_PITCAIRN_PM_A0;
break;
case CHIP_VERDE:
ws->family = FAMILY_SI;
ws->rev_id = SI_CAPEVERDE_M_A0;
break;
case CHIP_OLAND:
ws->family = FAMILY_SI;
ws->rev_id = SI_OLAND_M_A0;
break;
case CHIP_HAINAN:
ws->family = FAMILY_SI;
ws->rev_id = SI_HAINAN_V_A0;
break;
case CHIP_BONAIRE:
ws->family = FAMILY_CI;
ws->rev_id = CI_BONAIRE_M_A0;
break;
case CHIP_KAVERI:
ws->family = FAMILY_KV;
ws->rev_id = KV_SPECTRE_A0;
break;
case CHIP_KABINI:
ws->family = FAMILY_KV;
ws->rev_id = KB_KALINDI_A0;
break;
case CHIP_HAWAII:
ws->family = FAMILY_CI;
ws->rev_id = CI_HAWAII_P_A0;
break;
case CHIP_MULLINS:
ws->family = FAMILY_KV;
ws->rev_id = ML_GODAVARI_A0;
break;
case CHIP_TONGA:
ws->family = FAMILY_VI;
ws->rev_id = VI_TONGA_P_A0;
break;
case CHIP_ICELAND:
ws->family = FAMILY_VI;
ws->rev_id = VI_ICELAND_M_A0;
break;
case CHIP_CARRIZO:
ws->family = FAMILY_CZ;
ws->rev_id = CARRIZO_A0;
break;
case CHIP_STONEY:
ws->family = FAMILY_CZ;
ws->rev_id = STONEY_A0;
break;
case CHIP_FIJI:
ws->family = FAMILY_VI;
ws->rev_id = VI_FIJI_P_A0;
break;
case CHIP_POLARIS10:
ws->family = FAMILY_VI;
ws->rev_id = VI_POLARIS10_P_A0;
break;
case CHIP_POLARIS11:
ws->family = FAMILY_VI;
ws->rev_id = VI_POLARIS11_M_A0;
break;
default:
fprintf(stderr, "amdgpu: Unknown family.\n");
goto fail;
}
ws->addrlib = radv_amdgpu_addr_create(&ws->amdinfo, ws->family, ws->rev_id, ws->info.chip_class);
if (!ws->addrlib) {
fprintf(stderr, "amdgpu: Cannot create addrlib.\n");
goto fail;
}
/* Set hardware information. */
ws->info.name = get_chip_name(ws->info.family);
ws->info.gart_size = gtt.heap_size;
ws->info.vram_size = vram.heap_size;
/* convert the shader clock from KHz to MHz */
ws->info.max_shader_clock = ws->amdinfo.max_engine_clk / 1000;
ws->info.max_se = ws->amdinfo.num_shader_engines;
ws->info.max_sh_per_se = ws->amdinfo.num_shader_arrays_per_engine;
ws->info.has_uvd = 0;
ws->info.vce_fw_version = 0;
ws->info.has_userptr = TRUE;
ws->info.num_render_backends = ws->amdinfo.rb_pipes;
ws->info.clock_crystal_freq = ws->amdinfo.gpu_counter_freq;
ws->info.num_tile_pipes = radv_cik_get_num_tile_pipes(&ws->amdinfo);
ws->info.pipe_interleave_bytes = 256 << ((ws->amdinfo.gb_addr_cfg >> 4) & 0x7);
ws->info.has_virtual_memory = TRUE;
ws->info.has_sdma = dma.available_rings != 0;
/* Get the number of good compute units. */
ws->info.num_good_compute_units = 0;
for (i = 0; i < ws->info.max_se; i++)
for (j = 0; j < ws->info.max_sh_per_se; j++)
ws->info.num_good_compute_units +=
util_bitcount(ws->amdinfo.cu_bitmap[i][j]);
memcpy(ws->info.si_tile_mode_array, ws->amdinfo.gb_tile_mode,
sizeof(ws->amdinfo.gb_tile_mode));
ws->info.enabled_rb_mask = ws->amdinfo.enabled_rb_pipes_mask;
memcpy(ws->info.cik_macrotile_mode_array, ws->amdinfo.gb_macro_tile_mode,
sizeof(ws->amdinfo.gb_macro_tile_mode));
ws->info.gart_page_size = alignment_info.size_remote;
if (ws->info.chip_class == SI)
ws->info.gfx_ib_pad_with_type2 = TRUE;
ws->use_ib_bos = ws->family >= FAMILY_CI;
return true;
fail:
return false;
}
static void radv_amdgpu_winsys_query_info(struct radeon_winsys *rws,
struct radeon_info *info)
{
*info = ((struct radv_amdgpu_winsys *)rws)->info;
}
static void radv_amdgpu_winsys_destroy(struct radeon_winsys *rws)
{
struct radv_amdgpu_winsys *ws = (struct radv_amdgpu_winsys*)rws;
AddrDestroy(ws->addrlib);
amdgpu_device_deinitialize(ws->dev);
FREE(rws);
}
struct radeon_winsys *
radv_amdgpu_winsys_create(int fd)
{
uint32_t drm_major, drm_minor, r;
amdgpu_device_handle dev;
struct radv_amdgpu_winsys *ws;
r = amdgpu_device_initialize(fd, &drm_major, &drm_minor, &dev);
if (r)
return NULL;
ws = calloc(1, sizeof(struct radv_amdgpu_winsys));
if (!ws)
return NULL;
ws->dev = dev;
ws->info.drm_major = drm_major;
ws->info.drm_minor = drm_minor;
if (!do_winsys_init(ws, fd))
goto fail;
ws->debug_all_bos = getenv("RADV_DEBUG_ALL_BOS") ? true : false;
LIST_INITHEAD(&ws->global_bo_list);
pthread_mutex_init(&ws->global_bo_list_lock, NULL);
ws->base.query_info = radv_amdgpu_winsys_query_info;
ws->base.destroy = radv_amdgpu_winsys_destroy;
radv_amdgpu_bo_init_functions(ws);
radv_amdgpu_cs_init_functions(ws);
radv_amdgpu_surface_init_functions(ws);
return &ws->base;
fail:
return NULL;
}

View File

@ -0,0 +1,57 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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.
*/
#pragma once
#include "radv_radeon_winsys.h"
#include "addrlib/addrinterface.h"
#include <amdgpu.h>
#include "util/list.h"
struct radv_amdgpu_winsys {
struct radeon_winsys base;
amdgpu_device_handle dev;
struct radeon_info info;
struct amdgpu_gpu_info amdinfo;
ADDR_HANDLE addrlib;
uint32_t rev_id;
unsigned family;
bool debug_all_bos;
pthread_mutex_t global_bo_list_lock;
struct list_head global_bo_list;
unsigned num_buffers;
bool use_ib_bos;
};
static inline struct radv_amdgpu_winsys *
radv_amdgpu_winsys(struct radeon_winsys *base)
{
return (struct radv_amdgpu_winsys*)base;
}

View File

@ -0,0 +1,30 @@
/*
* Copyright © 2016 Red Hat.
* Copyright © 2016 Bas Nieuwenhuizen
*
* based on amdgpu winsys.
* Copyright © 2011 Marek Olšák <maraeo@gmail.com>
* Copyright © 2015 Advanced Micro Devices, Inc.
*
* 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.
*/
#pragma once
struct radeon_winsys *radv_amdgpu_winsys_create(int fd);