| /* |
| * © Copyright 2018 Alyssa Rosenzweig |
| * |
| * 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 "pan_format.h" |
| |
| /* From panwrap/panwrap-decoder, but we don't want to bring in all those headers */ |
| char *panwrap_format_name(enum mali_format format); |
| |
| /* Construct a default swizzle based on the number of components */ |
| |
| static unsigned |
| panfrost_translate_swizzle(enum pipe_swizzle s) |
| { |
| switch (s) { |
| case PIPE_SWIZZLE_X: |
| return MALI_CHANNEL_RED; |
| |
| case PIPE_SWIZZLE_Y: |
| return MALI_CHANNEL_GREEN; |
| |
| case PIPE_SWIZZLE_Z: |
| return MALI_CHANNEL_BLUE; |
| |
| case PIPE_SWIZZLE_W: |
| return MALI_CHANNEL_ALPHA; |
| |
| case PIPE_SWIZZLE_0: |
| case PIPE_SWIZZLE_NONE: |
| return MALI_CHANNEL_ZERO; |
| |
| case PIPE_SWIZZLE_1: |
| return MALI_CHANNEL_ONE; |
| |
| default: |
| unreachable("INvalid swizzle"); |
| } |
| } |
| |
| /* Translate a Gallium swizzle quad to a 12-bit Mali swizzle code */ |
| |
| unsigned |
| panfrost_translate_swizzle_4(const unsigned char swizzle[4]) |
| { |
| unsigned out = 0; |
| |
| for (unsigned i = 0; i < 4; ++i) { |
| unsigned translated = panfrost_translate_swizzle(swizzle[i]); |
| out |= (translated << (3*i)); |
| } |
| |
| return out; |
| } |
| |
| unsigned |
| panfrost_get_default_swizzle(unsigned components) |
| { |
| unsigned char default_swizzles[4][4] = { |
| {PIPE_SWIZZLE_X, PIPE_SWIZZLE_0, PIPE_SWIZZLE_0, PIPE_SWIZZLE_1}, |
| {PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_0, PIPE_SWIZZLE_1}, |
| {PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_1}, |
| {PIPE_SWIZZLE_X, PIPE_SWIZZLE_Y, PIPE_SWIZZLE_Z, PIPE_SWIZZLE_W}, |
| }; |
| |
| assert(components >= 1 && components <= 4); |
| return panfrost_translate_swizzle_4(default_swizzles[components - 1]); |
| } |
| |
| static unsigned |
| panfrost_translate_channel_width(unsigned size) |
| { |
| switch (size) { |
| case 4: |
| return MALI_CHANNEL_4; |
| case 8: |
| return MALI_CHANNEL_8; |
| case 16: |
| return MALI_CHANNEL_16; |
| case 32: |
| return MALI_CHANNEL_32; |
| default: |
| unreachable("Invalid width"); |
| } |
| } |
| |
| static unsigned |
| panfrost_translate_channel_type(unsigned type, unsigned size, bool norm) |
| { |
| switch (type) { |
| case UTIL_FORMAT_TYPE_UNSIGNED: |
| return norm ? MALI_FORMAT_UNORM : MALI_FORMAT_UINT; |
| |
| case UTIL_FORMAT_TYPE_SIGNED: |
| return norm ? MALI_FORMAT_SNORM : MALI_FORMAT_SINT; |
| |
| case UTIL_FORMAT_TYPE_FLOAT: |
| if (size == 16) { |
| /* With FLOAT, fp16 */ |
| return MALI_FORMAT_SINT; |
| } else if (size == 32) { |
| /* With FLOAT< fp32 */ |
| return MALI_FORMAT_UNORM; |
| } else { |
| assert(0); |
| return 0; |
| } |
| |
| default: |
| unreachable("Invalid type"); |
| } |
| } |
| |
| /* Constructs a mali_format satisfying the specified Gallium format |
| * description */ |
| |
| enum mali_format |
| panfrost_find_format(const struct util_format_description *desc) { |
| /* Find first non-VOID channel */ |
| struct util_format_channel_description chan = desc->channel[0]; |
| |
| for (unsigned c = 0; c < 4; ++c) |
| { |
| if (desc->channel[c].type == UTIL_FORMAT_TYPE_VOID) |
| continue; |
| |
| chan = desc->channel[c]; |
| break; |
| } |
| |
| /* Check for special formats */ |
| switch (desc->format) |
| { |
| case PIPE_FORMAT_YV12: |
| case PIPE_FORMAT_YV16: |
| case PIPE_FORMAT_IYUV: |
| case PIPE_FORMAT_NV21: |
| fprintf(stderr, "YUV format type %s (%d) is not yet supported, but it's probably close to NV12!\n", desc->name, desc->format); |
| assert(0); |
| break; |
| |
| case PIPE_FORMAT_NV12: |
| return MALI_NV12; |
| |
| case PIPE_FORMAT_R10G10B10X2_UNORM: |
| case PIPE_FORMAT_B10G10R10X2_UNORM: |
| case PIPE_FORMAT_R10G10B10A2_UNORM: |
| case PIPE_FORMAT_B10G10R10A2_UNORM: |
| return MALI_RGB10_A2_UNORM; |
| |
| case PIPE_FORMAT_R10G10B10X2_SNORM: |
| case PIPE_FORMAT_R10G10B10A2_SNORM: |
| case PIPE_FORMAT_B10G10R10A2_SNORM: |
| return MALI_RGB10_A2_SNORM; |
| |
| case PIPE_FORMAT_R10G10B10A2_UINT: |
| case PIPE_FORMAT_B10G10R10A2_UINT: |
| return MALI_RGB10_A2UI; |
| |
| /* TODO: ZS isn't really special case */ |
| case PIPE_FORMAT_Z32_UNORM: |
| return MALI_Z32_UNORM; |
| |
| case PIPE_FORMAT_B5G6R5_UNORM: |
| return MALI_RGB565; |
| |
| case PIPE_FORMAT_B5G5R5A1_UNORM: |
| return MALI_RGB5_A1_UNORM; |
| |
| case PIPE_FORMAT_A1B5G5R5_UNORM: |
| case PIPE_FORMAT_X1B5G5R5_UNORM: |
| /* Not supported - this is backwards from OpenGL! */ |
| assert(0); |
| break; |
| |
| case PIPE_FORMAT_R32_FIXED: |
| return MALI_R32_FIXED; |
| case PIPE_FORMAT_R32G32_FIXED: |
| return MALI_RG32_FIXED; |
| case PIPE_FORMAT_R32G32B32_FIXED: |
| return MALI_RGB32_FIXED; |
| case PIPE_FORMAT_R32G32B32A32_FIXED: |
| return MALI_RGBA32_FIXED; |
| |
| case PIPE_FORMAT_R11G11B10_FLOAT: |
| return MALI_R11F_G11F_B10F; |
| case PIPE_FORMAT_R9G9B9E5_FLOAT: |
| return MALI_R9F_G9F_B9F_E5F; |
| |
| default: |
| /* Fallthrough to default */ |
| break; |
| } |
| |
| /* Formats must match in channel count */ |
| assert(desc->nr_channels >= 1 && desc->nr_channels <= 4); |
| unsigned format = MALI_NR_CHANNELS(desc->nr_channels); |
| |
| switch (chan.type) |
| { |
| case UTIL_FORMAT_TYPE_UNSIGNED: |
| case UTIL_FORMAT_TYPE_SIGNED: |
| case UTIL_FORMAT_TYPE_FIXED: |
| /* Channel width */ |
| format |= panfrost_translate_channel_width(chan.size); |
| |
| /* Channel type */ |
| format |= panfrost_translate_channel_type(chan.type, chan.size, chan.normalized); |
| break; |
| |
| case UTIL_FORMAT_TYPE_FLOAT: |
| /* Float formats use a special width and encode width |
| * with type mixed */ |
| |
| format |= MALI_CHANNEL_FLOAT; |
| format |= panfrost_translate_channel_type(chan.type, chan.size, chan.normalized); |
| break; |
| |
| default: |
| printf("%s\n", util_format_name(desc->format)); |
| unreachable("Invalid format type"); |
| } |
| |
| return (enum mali_format) format; |
| } |
| |
| |