/* * Copyright © Microsoft Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "d3d12_format.h" #include "pipe/p_format.h" #include "pipe/p_video_enums.h" #include "util/format/u_format.h" #include "util/u_math.h" #include "util/compiler.h" #define MAP_FORMAT_YUV(NAME) \ [PIPE_FORMAT_ ## NAME] = DXGI_FORMAT_ ## NAME, #define MAP_FORMAT_NO_TYPELESS(BITS, TYPE) \ [PIPE_FORMAT_ ## BITS ## _ ## TYPE] = DXGI_FORMAT_ ## BITS ## _ ## TYPE, #define MAP_FORMAT2_NO_TYPELESS(BITS1, TYPE1, BITS2, TYPE2) \ [PIPE_FORMAT_ ## BITS1 ## _ ## TYPE1] = DXGI_FORMAT_ ## BITS2 ## _ ## TYPE2, #define MAP_FORMAT(BITS, TYPE) MAP_FORMAT_NO_TYPELESS(BITS, TYPE) #define MAP_FORMAT2(BITS1, TYPE1, BITS2, TYPE2) \ MAP_FORMAT2_NO_TYPELESS(BITS1, TYPE1, BITS2, TYPE2) #define MAP_FORMAT_CUSTOM_TYPELESS(BITS, TYPE, TYPELESS_BITS) \ MAP_FORMAT(BITS, TYPE) #define MAP_FORMAT2_CUSTOM_TYPELESS(BITS1, TYPE1, BITS2, TYPE2) \ MAP_FORMAT2(BITS1, TYPE1, BITS2, TYPE2) #define MAP_FORMAT_NORM(FMT) \ MAP_FORMAT(FMT, UNORM) \ MAP_FORMAT(FMT, SNORM) #define MAP_FORMAT_INT(FMT) \ MAP_FORMAT(FMT, UINT) \ MAP_FORMAT(FMT, SINT) #define MAP_FORMAT_SRGB(FMT) \ MAP_FORMAT2(FMT, SRGB, FMT, UNORM_SRGB) #define MAP_FORMAT_FLOAT(FMT) \ MAP_FORMAT(FMT, FLOAT) #define MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE) \ MAP_FORMAT2(L ## BITS, TYPE, R ## BITS, TYPE) \ MAP_FORMAT2(I ## BITS, TYPE, R ## BITS, TYPE) \ MAP_FORMAT2(L ## BITS ## A ## BITS, TYPE, R ## BITS ## G ## BITS, TYPE) #define MAP_EMU_FORMAT(BITS, TYPE) \ MAP_FORMAT2(A ## BITS, TYPE, R ## BITS, TYPE) \ MAP_EMU_FORMAT_NO_ALPHA(BITS, TYPE) #define MAP_FORMAT_X8(BITS, TYPE) \ MAP_FORMAT2(BITS ## X8, TYPE, BITS ## A8, TYPE) \ #define FORMAT_TABLE() \ MAP_FORMAT_NORM(R8) \ MAP_FORMAT_INT(R8) \ \ MAP_FORMAT_NORM(R8G8) \ MAP_FORMAT_INT(R8G8) \ \ MAP_FORMAT_NORM(R8G8B8A8) \ MAP_FORMAT_INT(R8G8B8A8) \ MAP_FORMAT_SRGB(R8G8B8A8) \ \ /* Since we report PIPE_CAP_RGB_OVERRIDE_DST_ALPHA_BLEND and other caps, \ * we can rely on st/mesa to force the alpha to 1 for these, so we can \ * just use RGBA. This is needed to support RGB configs, since some apps \ * will only choose RGB (not RGBA) configs. \ */ \ MAP_FORMAT_X8(R8G8B8, UNORM) \ MAP_FORMAT_X8(R8G8B8, SNORM) \ MAP_FORMAT_X8(R8G8B8, UINT) \ MAP_FORMAT_X8(R8G8B8, SINT) \ \ MAP_FORMAT(B8G8R8X8, UNORM) \ MAP_FORMAT(B8G8R8A8, UNORM) \ \ MAP_FORMAT_SRGB(B8G8R8A8) \ \ MAP_FORMAT_INT(R32) \ MAP_FORMAT_FLOAT(R32) \ MAP_FORMAT_INT(R32G32) \ MAP_FORMAT_FLOAT(R32G32) \ MAP_FORMAT_INT(R32G32B32) \ MAP_FORMAT_FLOAT(R32G32B32) \ MAP_FORMAT_INT(R32G32B32A32) \ MAP_FORMAT_FLOAT(R32G32B32A32) \ \ MAP_FORMAT_NORM(R16) \ MAP_FORMAT_INT(R16) \ MAP_FORMAT_FLOAT(R16) \ \ MAP_FORMAT_NORM(R16G16) \ MAP_FORMAT_INT(R16G16) \ MAP_FORMAT_FLOAT(R16G16) \ \ MAP_FORMAT_NORM(R16G16B16A16) \ MAP_FORMAT_INT(R16G16B16A16) \ MAP_FORMAT_FLOAT(R16G16B16A16) \ \ MAP_FORMAT_NO_TYPELESS(A8, UNORM) \ MAP_EMU_FORMAT_NO_ALPHA(8, UNORM) \ MAP_EMU_FORMAT(8, SNORM) \ MAP_EMU_FORMAT(8, SINT) \ MAP_EMU_FORMAT(8, UINT) \ MAP_EMU_FORMAT(16, UNORM) \ MAP_EMU_FORMAT(16, SNORM) \ MAP_EMU_FORMAT(16, SINT) \ MAP_EMU_FORMAT(16, UINT) \ MAP_EMU_FORMAT(16, FLOAT) \ MAP_EMU_FORMAT(32, SINT) \ MAP_EMU_FORMAT(32, UINT) \ MAP_EMU_FORMAT(32, FLOAT) \ \ MAP_FORMAT2_NO_TYPELESS(R9G9B9E5, FLOAT, R9G9B9E5, SHAREDEXP) \ MAP_FORMAT_NO_TYPELESS(R11G11B10, FLOAT) \ MAP_FORMAT(R10G10B10A2, UINT) \ MAP_FORMAT(R10G10B10A2, UNORM) \ \ MAP_FORMAT_NO_TYPELESS(B5G6R5, UNORM) \ MAP_FORMAT_NO_TYPELESS(B5G5R5A1, UNORM) \ MAP_FORMAT2_NO_TYPELESS(B5G5R5X1, UNORM, B5G5R5A1, UNORM) \ \ MAP_FORMAT_NO_TYPELESS(B4G4R4A4, UNORM) \ \ MAP_FORMAT2(DXT1, RGB, BC1, UNORM) \ MAP_FORMAT2(DXT1, RGBA, BC1, UNORM) \ MAP_FORMAT2(DXT3, RGBA, BC2, UNORM) \ MAP_FORMAT2(DXT5, RGBA, BC3, UNORM) \ \ MAP_FORMAT2(DXT1, SRGB, BC1, UNORM_SRGB) \ MAP_FORMAT2(DXT1, SRGBA, BC1, UNORM_SRGB) \ MAP_FORMAT2(DXT3, SRGBA, BC2, UNORM_SRGB) \ MAP_FORMAT2(DXT5, SRGBA, BC3, UNORM_SRGB) \ \ MAP_FORMAT2(RGTC1, UNORM, BC4, UNORM) \ MAP_FORMAT2(RGTC1, SNORM, BC4, SNORM) \ MAP_FORMAT2(RGTC2, UNORM, BC5, UNORM) \ MAP_FORMAT2(RGTC2, SNORM, BC5, SNORM) \ \ MAP_FORMAT2(BPTC, RGBA_UNORM, BC7, UNORM) \ MAP_FORMAT2(BPTC, SRGBA, BC7, UNORM_SRGB) \ MAP_FORMAT2(BPTC, RGB_FLOAT, BC6H, SF16) \ MAP_FORMAT2(BPTC, RGB_UFLOAT, BC6H, UF16) \ \ MAP_FORMAT2(Z32, FLOAT, R32, TYPELESS) \ MAP_FORMAT2(Z16, UNORM, R16, TYPELESS) \ MAP_FORMAT2(Z24X8, UNORM, R24G8, TYPELESS) \ MAP_FORMAT2(X24S8, UINT, R24G8, TYPELESS) \ \ MAP_FORMAT2(Z24_UNORM_S8, UINT, R24G8, TYPELESS) \ MAP_FORMAT2(Z32_FLOAT_S8X24, UINT, R32G8X24, TYPELESS) \ MAP_FORMAT2(X32_S8X24, UINT, R32G8X24, TYPELESS) \ \ MAP_FORMAT_YUV(NV12) static const DXGI_FORMAT formats[PIPE_FORMAT_COUNT] = { FORMAT_TABLE() }; #undef MAP_FORMAT #undef MAP_FORMAT2 #undef MAP_FORMAT_CUSTOM_TYPELESS #undef MAP_FORMAT2_CUSTOM_TYPELESS #define MAP_FORMAT(BITS, TYPE) \ [PIPE_FORMAT_ ## BITS ## _ ## TYPE] = DXGI_FORMAT_ ## BITS ## _TYPELESS, #define MAP_FORMAT2(BITS1, TYPE1, BITS2, TYPE2) \ [PIPE_FORMAT_ ## BITS1 ## _ ## TYPE1] = DXGI_FORMAT_ ## BITS2 ## _TYPELESS, #define MAP_FORMAT_CUSTOM_TYPELESS(BITS1, TYPE, BITS2) \ MAP_FORMAT2(BITS1, TYPE, BITS2, TYPELESS) #define MAP_FORMAT2_CUSTOM_TYPELESS(BITS1, TYPE1, BITS2, TYPE2) \ MAP_FORMAT2(BITS1, TYPE1, BITS2, TYPELESS) static const DXGI_FORMAT typeless_formats[PIPE_FORMAT_COUNT] = { FORMAT_TABLE() }; DXGI_FORMAT d3d12_get_format(enum pipe_format format) { return formats[format]; } DXGI_FORMAT d3d12_get_typeless_format(enum pipe_format format) { return typeless_formats[format]; } enum pipe_format d3d12_get_pipe_format(DXGI_FORMAT format) { for (unsigned i = 0; i < ARRAY_SIZE(formats); ++i) { if (formats[i] == format) { return (enum pipe_format)i; } } return PIPE_FORMAT_NONE; } enum pipe_format d3d12_get_default_pipe_format(DXGI_FORMAT format) { #define TYPELESS_TO(channels, suffix) \ case DXGI_FORMAT_##channels##_TYPELESS: \ return PIPE_FORMAT_##channels##_##suffix switch (format) { TYPELESS_TO(R8, UNORM); TYPELESS_TO(R8G8, UNORM); TYPELESS_TO(R8G8B8A8, UNORM); TYPELESS_TO(B8G8R8X8, UNORM); TYPELESS_TO(B8G8R8A8, UNORM); TYPELESS_TO(R16, FLOAT); TYPELESS_TO(R16G16, FLOAT); TYPELESS_TO(R16G16B16A16, FLOAT); TYPELESS_TO(R32, FLOAT); TYPELESS_TO(R32G32, FLOAT); TYPELESS_TO(R32G32B32, FLOAT); TYPELESS_TO(R32G32B32A32, FLOAT); case DXGI_FORMAT_BC1_TYPELESS: return PIPE_FORMAT_DXT1_RGBA; case DXGI_FORMAT_BC2_TYPELESS: return PIPE_FORMAT_DXT3_RGBA; case DXGI_FORMAT_BC3_TYPELESS: return PIPE_FORMAT_DXT5_RGBA; case DXGI_FORMAT_BC4_TYPELESS: return PIPE_FORMAT_RGTC1_UNORM; case DXGI_FORMAT_BC5_TYPELESS: return PIPE_FORMAT_RGTC2_UNORM; case DXGI_FORMAT_BC6H_TYPELESS: return PIPE_FORMAT_BPTC_RGB_FLOAT; case DXGI_FORMAT_BC7_TYPELESS: return PIPE_FORMAT_BPTC_RGBA_UNORM; default: return PIPE_FORMAT_NONE; } } DXGI_FORMAT d3d12_get_resource_rt_format(enum pipe_format f) { switch (f) { case PIPE_FORMAT_Z16_UNORM: return DXGI_FORMAT_D16_UNORM; case PIPE_FORMAT_Z32_FLOAT: return DXGI_FORMAT_D32_FLOAT; case PIPE_FORMAT_Z24X8_UNORM: case PIPE_FORMAT_X24S8_UINT: return DXGI_FORMAT_D24_UNORM_S8_UINT; case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: case PIPE_FORMAT_X32_S8X24_UINT: return DXGI_FORMAT_D32_FLOAT_S8X24_UINT; case PIPE_FORMAT_Z24_UNORM_S8_UINT: return DXGI_FORMAT_D24_UNORM_S8_UINT; default: return d3d12_get_format(f); } } DXGI_FORMAT d3d12_get_resource_srv_format(enum pipe_format f, enum pipe_texture_target target) { switch (f) { case PIPE_FORMAT_Z16_UNORM: return DXGI_FORMAT_R16_UNORM; case PIPE_FORMAT_Z32_FLOAT: return DXGI_FORMAT_R32_FLOAT; case PIPE_FORMAT_Z24X8_UNORM: case PIPE_FORMAT_Z24_UNORM_S8_UINT: return DXGI_FORMAT_R24_UNORM_X8_TYPELESS; case PIPE_FORMAT_X24S8_UINT: return DXGI_FORMAT_X24_TYPELESS_G8_UINT; case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS; case PIPE_FORMAT_X32_S8X24_UINT: return DXGI_FORMAT_X32_TYPELESS_G8X24_UINT; case PIPE_FORMAT_A8_UNORM: if (target == PIPE_BUFFER) return DXGI_FORMAT_R8_UNORM; /* A8_UNORM is not supported for buffer SRV */ FALLTHROUGH; default: return d3d12_get_format(f); } } #define DEF_SWIZZLE(name, X, Y, Z, W) \ static const enum pipe_swizzle name ## _SWIZZLE[PIPE_SWIZZLE_MAX] = \ { PIPE_SWIZZLE_ ## X, PIPE_SWIZZLE_ ## Y, PIPE_SWIZZLE_ ## Z, PIPE_SWIZZLE_ ## W, \ PIPE_SWIZZLE_0, PIPE_SWIZZLE_1, PIPE_SWIZZLE_NONE } struct d3d12_format_info d3d12_get_format_info(enum pipe_format resource_format, enum pipe_format pformat, enum pipe_texture_target target) { DEF_SWIZZLE(IDENTITY, X, Y, Z, W); DEF_SWIZZLE(RGB1, X, Y, Z, 1); DEF_SWIZZLE(ALPHA, 0, 0, 0, W); DEF_SWIZZLE(BUFFER, 0, 0, 0, X); DEF_SWIZZLE(INTENSITY, X, X, X, X); DEF_SWIZZLE(LUMINANCE, X, X, X, 1); DEF_SWIZZLE(LUMINANCE_ALPHA, X, X, X, Y); DEF_SWIZZLE(DEPTH, X, X, X, X); DEF_SWIZZLE(STENCIL, Y, Y, Y, Y); const enum pipe_swizzle *swizzle = IDENTITY_SWIZZLE; unsigned plane_slice = 0; if (pformat == PIPE_FORMAT_DXT1_RGB || pformat == PIPE_FORMAT_DXT1_SRGB) swizzle = RGB1_SWIZZLE; const struct util_format_description *format_desc = util_format_description(pformat); unsigned plane_count = util_format_get_num_planes(resource_format); if (!util_format_is_srgb(pformat)) { if (target == PIPE_BUFFER && util_format_is_alpha(pformat)) { swizzle = BUFFER_SWIZZLE; } else if (plane_count > 1) { for (plane_slice = 0; plane_slice < plane_count; ++plane_slice) { if (util_format_get_plane_format(resource_format, plane_slice) == pformat) break; } assert(plane_slice < plane_count); } else if (pformat == PIPE_FORMAT_A8_UNORM) { /* no need to swizzle, it's natively supported */ } else if (util_format_is_intensity(pformat)) { swizzle = INTENSITY_SWIZZLE; } else if (util_format_is_luminance(pformat)) { swizzle = LUMINANCE_SWIZZLE; } else if (util_format_is_luminance_alpha(pformat)) { swizzle = LUMINANCE_ALPHA_SWIZZLE; } else if (util_format_is_alpha(pformat)) { swizzle = ALPHA_SWIZZLE; } else if (util_format_has_depth(format_desc)) { swizzle = DEPTH_SWIZZLE; } else if (util_format_has_stencil(format_desc)) { /* When reading from a stencil texture we have to use plane 1, and * the formats X24S8 and X32_S8X24 have the actual data in the y-channel * but the shader will read the x component so we need to adjust the swizzle. */ plane_slice = 1; swizzle = STENCIL_SWIZZLE; } else if (util_format_has_alpha1(pformat)) { swizzle = RGB1_SWIZZLE; } } return (struct d3d12_format_info) { .swizzle = swizzle, .plane_slice = plane_slice }; } enum pipe_format d3d12_emulated_vtx_format(enum pipe_format fmt) { switch (fmt) { case PIPE_FORMAT_R10G10B10A2_SNORM: case PIPE_FORMAT_R10G10B10A2_SSCALED: case PIPE_FORMAT_R10G10B10A2_USCALED: case PIPE_FORMAT_B10G10R10A2_UNORM: case PIPE_FORMAT_B10G10R10A2_SNORM: case PIPE_FORMAT_B10G10R10A2_SSCALED: case PIPE_FORMAT_B10G10R10A2_USCALED: return PIPE_FORMAT_R32_UINT; case PIPE_FORMAT_R8G8B8_SINT: return PIPE_FORMAT_R8G8B8A8_SINT; case PIPE_FORMAT_R8G8B8_UINT: return PIPE_FORMAT_R8G8B8A8_UINT; case PIPE_FORMAT_R16G16B16_SINT: return PIPE_FORMAT_R16G16B16A16_SINT; case PIPE_FORMAT_R16G16B16_UINT: return PIPE_FORMAT_R16G16B16A16_UINT; case PIPE_FORMAT_R8G8B8A8_SSCALED: return PIPE_FORMAT_R8G8B8A8_SINT; case PIPE_FORMAT_R8G8B8A8_USCALED: return PIPE_FORMAT_R8G8B8A8_UINT; case PIPE_FORMAT_R16G16B16A16_SSCALED: return PIPE_FORMAT_R16G16B16A16_SINT; case PIPE_FORMAT_R16G16B16A16_USCALED: return PIPE_FORMAT_R16G16B16A16_UINT; default: return fmt; } } unsigned d3d12_non_opaque_plane_count(DXGI_FORMAT format) { switch (format) { case DXGI_FORMAT_V208: case DXGI_FORMAT_V408: return 3; case DXGI_FORMAT_NV12: case DXGI_FORMAT_P010: case DXGI_FORMAT_P016: case DXGI_FORMAT_YUY2: case DXGI_FORMAT_Y210: case DXGI_FORMAT_Y216: case DXGI_FORMAT_NV11: return 2; case DXGI_FORMAT_R24G8_TYPELESS: case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: case DXGI_FORMAT_X24_TYPELESS_G8_UINT: case DXGI_FORMAT_D24_UNORM_S8_UINT: case DXGI_FORMAT_R32G8X24_TYPELESS: case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: return 2; default: return 1; } } unsigned d3d12_get_format_start_plane(enum pipe_format fmt) { const struct util_format_description *desc = util_format_description(fmt); if (util_format_has_stencil(desc) && !util_format_has_depth(desc)) return 1; return 0; } unsigned d3d12_get_format_num_planes(enum pipe_format fmt) { return util_format_is_depth_or_stencil(fmt) ? util_bitcount(util_format_get_mask(fmt)) : 1; } DXGI_FORMAT d3d12_convert_pipe_video_profile_to_dxgi_format(enum pipe_video_profile profile) { switch (profile) { case PIPE_VIDEO_PROFILE_MPEG4_AVC_BASELINE: case PIPE_VIDEO_PROFILE_MPEG4_AVC_CONSTRAINED_BASELINE: case PIPE_VIDEO_PROFILE_MPEG4_AVC_MAIN: case PIPE_VIDEO_PROFILE_MPEG4_AVC_EXTENDED: case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH: return DXGI_FORMAT_NV12; case PIPE_VIDEO_PROFILE_MPEG4_AVC_HIGH10: return DXGI_FORMAT_P010; default: { unreachable("Unsupported pipe video profile"); } break; } } DXGI_COLOR_SPACE_TYPE d3d12_convert_from_legacy_color_space(bool rgb, uint32_t bits_per_element, bool studio_rgb, bool p709, bool studio_yuv) { if (rgb) { if (bits_per_element > 32) { // All 16 bit color channel data is assumed to be linear rather than SRGB return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709; } else { if (studio_rgb) { return DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P709; } else { return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709; } } } else { if (p709) { if (studio_yuv) { return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P709; } else { return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P709; } } else { if (studio_yuv) { return DXGI_COLOR_SPACE_YCBCR_STUDIO_G22_LEFT_P601; } else { return DXGI_COLOR_SPACE_YCBCR_FULL_G22_LEFT_P601; } } } }