Path: blob/21.2-virgl/src/util/format/u_format.c
7110 views
/**************************************************************************1*2* Copyright 2010 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/**28* @file29* Pixel format accessor functions.30*31* @author Jose Fonseca <[email protected]>32*/3334#include "util/format/u_format.h"35#include "util/format/u_format_s3tc.h"36#include "util/u_cpu_detect.h"37#include "util/u_math.h"3839#include "pipe/p_defines.h"40#include "pipe/p_screen.h"414243/**44* Copy 2D rect from one place to another.45* Position and sizes are in pixels.46* src_stride may be negative to do vertical flip of pixels from source.47*/48void49util_copy_rect(ubyte * dst,50enum pipe_format format,51unsigned dst_stride,52unsigned dst_x,53unsigned dst_y,54unsigned width,55unsigned height,56const ubyte * src,57int src_stride,58unsigned src_x,59unsigned src_y)60{61unsigned i;62int src_stride_pos = src_stride < 0 ? -src_stride : src_stride;63int blocksize = util_format_get_blocksize(format);64int blockwidth = util_format_get_blockwidth(format);65int blockheight = util_format_get_blockheight(format);6667assert(blocksize > 0);68assert(blockwidth > 0);69assert(blockheight > 0);7071dst_x /= blockwidth;72dst_y /= blockheight;73width = (width + blockwidth - 1)/blockwidth;74height = (height + blockheight - 1)/blockheight;75src_x /= blockwidth;76src_y /= blockheight;7778dst += dst_x * blocksize;79src += src_x * blocksize;80dst += dst_y * dst_stride;81src += src_y * src_stride_pos;82width *= blocksize;8384if (width == dst_stride && width == (unsigned)src_stride)85memcpy(dst, src, height * width);86else {87for (i = 0; i < height; i++) {88memcpy(dst, src, width);89dst += dst_stride;90src += src_stride;91}92}93}949596boolean97util_format_is_float(enum pipe_format format)98{99const struct util_format_description *desc = util_format_description(format);100int i;101102assert(desc);103if (!desc) {104return FALSE;105}106107i = util_format_get_first_non_void_channel(format);108if (i < 0) {109return FALSE;110}111112return desc->channel[i].type == UTIL_FORMAT_TYPE_FLOAT ? TRUE : FALSE;113}114115116/** Test if the format contains RGB, but not alpha */117boolean118util_format_has_alpha(enum pipe_format format)119{120const struct util_format_description *desc =121util_format_description(format);122123return (desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||124desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&125desc->swizzle[3] != PIPE_SWIZZLE_1;126}127128/** Test if format has alpha as 1 (like RGBX) */129boolean130util_format_has_alpha1(enum pipe_format format)131{132const struct util_format_description *desc =133util_format_description(format);134135return (desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||136desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&137desc->nr_channels == 4 &&138desc->swizzle[3] == PIPE_SWIZZLE_1;139}140141boolean142util_format_is_luminance(enum pipe_format format)143{144const struct util_format_description *desc =145util_format_description(format);146147if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||148desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&149desc->swizzle[0] == PIPE_SWIZZLE_X &&150desc->swizzle[1] == PIPE_SWIZZLE_X &&151desc->swizzle[2] == PIPE_SWIZZLE_X &&152desc->swizzle[3] == PIPE_SWIZZLE_1) {153return TRUE;154}155return FALSE;156}157158boolean159util_format_is_alpha(enum pipe_format format)160{161const struct util_format_description *desc =162util_format_description(format);163164if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||165desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&166desc->swizzle[0] == PIPE_SWIZZLE_0 &&167desc->swizzle[1] == PIPE_SWIZZLE_0 &&168desc->swizzle[2] == PIPE_SWIZZLE_0 &&169desc->swizzle[3] == PIPE_SWIZZLE_X) {170return TRUE;171}172return FALSE;173}174175boolean176util_format_is_pure_integer(enum pipe_format format)177{178const struct util_format_description *desc = util_format_description(format);179int i;180181/* Find the first non-void channel. */182i = util_format_get_first_non_void_channel(format);183if (i == -1)184return FALSE;185186return desc->channel[i].pure_integer ? TRUE : FALSE;187}188189boolean190util_format_is_pure_sint(enum pipe_format format)191{192const struct util_format_description *desc = util_format_description(format);193int i;194195i = util_format_get_first_non_void_channel(format);196if (i == -1)197return FALSE;198199return (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;200}201202boolean203util_format_is_pure_uint(enum pipe_format format)204{205const struct util_format_description *desc = util_format_description(format);206int i;207208i = util_format_get_first_non_void_channel(format);209if (i == -1)210return FALSE;211212return (desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED && desc->channel[i].pure_integer) ? TRUE : FALSE;213}214215/**216* Returns true if the format contains normalized signed channels.217*/218boolean219util_format_is_snorm(enum pipe_format format)220{221const struct util_format_description *desc = util_format_description(format);222223return desc->is_snorm;224}225226/**227* Returns true if the format contains normalized unsigned channels.228*/229boolean230util_format_is_unorm(enum pipe_format format)231{232const struct util_format_description *desc = util_format_description(format);233234return desc->is_unorm;235}236237/**238* Returns true if the format contains scaled integer format channels.239*/240boolean241util_format_is_scaled(enum pipe_format format)242{243const struct util_format_description *desc = util_format_description(format);244int i;245246/* format none is described as scaled but not for this check */247if (format == PIPE_FORMAT_NONE)248return FALSE;249250/* Find the first non-void channel. */251i = util_format_get_first_non_void_channel(format);252if (i == -1)253return FALSE;254255return !desc->channel[i].pure_integer && !desc->channel[i].normalized &&256(desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED ||257desc->channel[i].type == UTIL_FORMAT_TYPE_UNSIGNED);258}259260boolean261util_format_is_snorm8(enum pipe_format format)262{263const struct util_format_description *desc = util_format_description(format);264int i;265266if (desc->is_mixed)267return FALSE;268269i = util_format_get_first_non_void_channel(format);270if (i == -1)271return FALSE;272273return desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED &&274!desc->channel[i].pure_integer &&275desc->channel[i].normalized &&276desc->channel[i].size == 8;277}278279boolean280util_format_is_luminance_alpha(enum pipe_format format)281{282const struct util_format_description *desc =283util_format_description(format);284285if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||286desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&287desc->swizzle[0] == PIPE_SWIZZLE_X &&288desc->swizzle[1] == PIPE_SWIZZLE_X &&289desc->swizzle[2] == PIPE_SWIZZLE_X &&290desc->swizzle[3] == PIPE_SWIZZLE_Y) {291return TRUE;292}293return FALSE;294}295296297boolean298util_format_is_intensity(enum pipe_format format)299{300const struct util_format_description *desc =301util_format_description(format);302303if ((desc->colorspace == UTIL_FORMAT_COLORSPACE_RGB ||304desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) &&305desc->swizzle[0] == PIPE_SWIZZLE_X &&306desc->swizzle[1] == PIPE_SWIZZLE_X &&307desc->swizzle[2] == PIPE_SWIZZLE_X &&308desc->swizzle[3] == PIPE_SWIZZLE_X) {309return TRUE;310}311return FALSE;312}313314boolean315util_format_is_subsampled_422(enum pipe_format format)316{317const struct util_format_description *desc =318util_format_description(format);319320return desc->layout == UTIL_FORMAT_LAYOUT_SUBSAMPLED &&321desc->block.width == 2 &&322desc->block.height == 1 &&323desc->block.bits == 32;324}325326/**327* Calculates the MRD for the depth format. MRD is used in depth bias328* for UNORM and unbound depth buffers. When the depth buffer is floating329* point, the depth bias calculation does not use the MRD. However, the330* default MRD will be 1.0 / ((1 << 24) - 1).331*/332double333util_get_depth_format_mrd(const struct util_format_description *desc)334{335/*336* Depth buffer formats without a depth component OR scenarios337* without a bound depth buffer default to D24.338*/339double mrd = 1.0 / ((1 << 24) - 1);340unsigned depth_channel;341342assert(desc);343344/*345* Some depth formats do not store the depth component in the first346* channel, detect the format and adjust the depth channel. Get the347* swizzled depth component channel.348*/349depth_channel = desc->swizzle[0];350351if (desc->channel[depth_channel].type == UTIL_FORMAT_TYPE_UNSIGNED &&352desc->channel[depth_channel].normalized) {353int depth_bits;354355depth_bits = desc->channel[depth_channel].size;356mrd = 1.0 / ((1ULL << depth_bits) - 1);357}358359return mrd;360}361362void363util_format_unpack_rgba_rect(enum pipe_format format,364void *dst, unsigned dst_stride,365const void *src, unsigned src_stride,366unsigned w, unsigned h)367{368const struct util_format_unpack_description *unpack =369util_format_unpack_description(format);370371/* Optimized function for block-compressed formats */372if (unpack->unpack_rgba_rect) {373unpack->unpack_rgba_rect(dst, dst_stride, src, src_stride, w, h);374} else {375for (unsigned y = 0; y < h; y++) {376unpack->unpack_rgba(dst, src, w);377src = (const char *)src + src_stride;378dst = (char *)dst + dst_stride;379}380}381}382383void384util_format_unpack_rgba_8unorm_rect(enum pipe_format format,385void *dst, unsigned dst_stride,386const void *src, unsigned src_stride,387unsigned w, unsigned h)388{389const struct util_format_unpack_description *unpack =390util_format_unpack_description(format);391392/* Optimized function for block-compressed formats */393if (unpack->unpack_rgba_8unorm_rect) {394unpack->unpack_rgba_8unorm_rect(dst, dst_stride, src, src_stride, w, h);395} else {396for (unsigned y = 0; y < h; y++) {397unpack->unpack_rgba_8unorm(dst, src, w);398src = (const char *)src + src_stride;399dst = (char *)dst + dst_stride;400}401}402}403404void405util_format_read_4(enum pipe_format format,406void *dst, unsigned dst_stride,407const void *src, unsigned src_stride,408unsigned x, unsigned y, unsigned w, unsigned h)409{410const struct util_format_description *format_desc;411const uint8_t *src_row;412413format_desc = util_format_description(format);414415assert(x % format_desc->block.width == 0);416assert(y % format_desc->block.height == 0);417418src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);419420util_format_unpack_rgba_rect(format, dst, dst_stride, src_row, src_stride, w, h);421}422423424void425util_format_write_4(enum pipe_format format,426const void *src, unsigned src_stride,427void *dst, unsigned dst_stride,428unsigned x, unsigned y, unsigned w, unsigned h)429{430const struct util_format_description *format_desc;431const struct util_format_pack_description *pack =432util_format_pack_description(format);433uint8_t *dst_row;434435format_desc = util_format_description(format);436437assert(x % format_desc->block.width == 0);438assert(y % format_desc->block.height == 0);439440dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);441442if (util_format_is_pure_uint(format))443pack->pack_rgba_uint(dst_row, dst_stride, src, src_stride, w, h);444else if (util_format_is_pure_sint(format))445pack->pack_rgba_sint(dst_row, dst_stride, src, src_stride, w, h);446else447pack->pack_rgba_float(dst_row, dst_stride, src, src_stride, w, h);448}449450451void452util_format_read_4ub(enum pipe_format format, uint8_t *dst, unsigned dst_stride, const void *src, unsigned src_stride, unsigned x, unsigned y, unsigned w, unsigned h)453{454const struct util_format_description *format_desc;455const uint8_t *src_row;456457format_desc = util_format_description(format);458459assert(x % format_desc->block.width == 0);460assert(y % format_desc->block.height == 0);461462src_row = (const uint8_t *)src + y*src_stride + x*(format_desc->block.bits/8);463464util_format_unpack_rgba_8unorm_rect(format, dst, dst_stride, src_row, src_stride, w, h);465}466467468void469util_format_write_4ub(enum pipe_format format, const uint8_t *src, unsigned src_stride, void *dst, unsigned dst_stride, unsigned x, unsigned y, unsigned w, unsigned h)470{471const struct util_format_description *format_desc;472const struct util_format_pack_description *pack =473util_format_pack_description(format);474uint8_t *dst_row;475const uint8_t *src_row;476477format_desc = util_format_description(format);478479assert(x % format_desc->block.width == 0);480assert(y % format_desc->block.height == 0);481482dst_row = (uint8_t *)dst + y*dst_stride + x*(format_desc->block.bits/8);483src_row = src;484485pack->pack_rgba_8unorm(dst_row, dst_stride, src_row, src_stride, w, h);486}487488/**489* Check if we can safely memcopy from the source format to the dest format.490* This basically covers the cases of a "used" channel copied to a typeless491* channel, plus some 1-channel cases.492* Examples of compatible copy formats include:493* b8g8r8a8_unorm -> b8g8r8x8_unorm494* a8r8g8b8_unorm -> x8r8g8b8_unorm495* b5g5r5a1_unorm -> b5g5r5x1_unorm496* b4g4r4a4_unorm -> b4g4r4x4_unorm497* l8_unorm -> r8_unorm498* i8_unorm -> l8_unorm499* i8_unorm -> a8_unorm500* i8_unorm -> r8_unorm501* l16_unorm -> r16_unorm502* z24_unorm_s8_uint -> z24x8_unorm503* s8_uint_z24_unorm -> x8z24_unorm504* r8g8b8a8_unorm -> r8g8b8x8_unorm505* a8b8g8r8_srgb -> x8b8g8r8_srgb506* b8g8r8a8_srgb -> b8g8r8x8_srgb507* a8r8g8b8_srgb -> x8r8g8b8_srgb508* a8b8g8r8_unorm -> x8b8g8r8_unorm509* r10g10b10a2_uscaled -> r10g10b10x2_uscaled510* r10sg10sb10sa2u_norm -> r10g10b10x2_snorm511*/512boolean513util_is_format_compatible(const struct util_format_description *src_desc,514const struct util_format_description *dst_desc)515{516unsigned chan;517518if (src_desc->format == dst_desc->format) {519return TRUE;520}521522if (src_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN ||523dst_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {524return FALSE;525}526527if (src_desc->block.bits != dst_desc->block.bits ||528src_desc->nr_channels != dst_desc->nr_channels ||529src_desc->colorspace != dst_desc->colorspace) {530return FALSE;531}532533for (chan = 0; chan < 4; ++chan) {534if (src_desc->channel[chan].size !=535dst_desc->channel[chan].size) {536return FALSE;537}538}539540for (chan = 0; chan < 4; ++chan) {541enum pipe_swizzle swizzle = dst_desc->swizzle[chan];542543if (swizzle < 4) {544if (src_desc->swizzle[chan] != swizzle) {545return FALSE;546}547if ((src_desc->channel[swizzle].type !=548dst_desc->channel[swizzle].type) ||549(src_desc->channel[swizzle].normalized !=550dst_desc->channel[swizzle].normalized)) {551return FALSE;552}553}554}555556return TRUE;557}558559560boolean561util_format_fits_8unorm(const struct util_format_description *format_desc)562{563unsigned chan;564565/*566* After linearized sRGB values require more than 8bits.567*/568569if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {570return FALSE;571}572573switch (format_desc->layout) {574575case UTIL_FORMAT_LAYOUT_S3TC:576/*577* These are straight forward.578*/579return TRUE;580case UTIL_FORMAT_LAYOUT_RGTC:581if (format_desc->format == PIPE_FORMAT_RGTC1_SNORM ||582format_desc->format == PIPE_FORMAT_RGTC2_SNORM ||583format_desc->format == PIPE_FORMAT_LATC1_SNORM ||584format_desc->format == PIPE_FORMAT_LATC2_SNORM)585return FALSE;586return TRUE;587case UTIL_FORMAT_LAYOUT_BPTC:588if (format_desc->format == PIPE_FORMAT_BPTC_RGBA_UNORM)589return TRUE;590return FALSE;591592case UTIL_FORMAT_LAYOUT_ETC:593if (format_desc->format == PIPE_FORMAT_ETC1_RGB8)594return TRUE;595return FALSE;596597case UTIL_FORMAT_LAYOUT_PLAIN:598/*599* For these we can find a generic rule.600*/601602for (chan = 0; chan < format_desc->nr_channels; ++chan) {603switch (format_desc->channel[chan].type) {604case UTIL_FORMAT_TYPE_VOID:605break;606case UTIL_FORMAT_TYPE_UNSIGNED:607if (!format_desc->channel[chan].normalized ||608format_desc->channel[chan].size > 8) {609return FALSE;610}611break;612default:613return FALSE;614}615}616return TRUE;617618default:619/*620* Handle all others on a case by case basis.621*/622623switch (format_desc->format) {624case PIPE_FORMAT_R1_UNORM:625case PIPE_FORMAT_UYVY:626case PIPE_FORMAT_YUYV:627case PIPE_FORMAT_R8G8_B8G8_UNORM:628case PIPE_FORMAT_G8R8_G8B8_UNORM:629return TRUE;630631default:632return FALSE;633}634}635}636637638boolean639util_format_translate(enum pipe_format dst_format,640void *dst, unsigned dst_stride,641unsigned dst_x, unsigned dst_y,642enum pipe_format src_format,643const void *src, unsigned src_stride,644unsigned src_x, unsigned src_y,645unsigned width, unsigned height)646{647const struct util_format_description *dst_format_desc;648const struct util_format_description *src_format_desc;649const struct util_format_pack_description *pack =650util_format_pack_description(dst_format);651const struct util_format_unpack_description *unpack =652util_format_unpack_description(src_format);653uint8_t *dst_row;654const uint8_t *src_row;655unsigned x_step, y_step;656unsigned dst_step;657unsigned src_step;658659dst_format_desc = util_format_description(dst_format);660src_format_desc = util_format_description(src_format);661662if (util_is_format_compatible(src_format_desc, dst_format_desc)) {663/*664* Trivial case.665*/666667util_copy_rect(dst, dst_format, dst_stride, dst_x, dst_y,668width, height, src, (int)src_stride,669src_x, src_y);670return TRUE;671}672673assert(dst_x % dst_format_desc->block.width == 0);674assert(dst_y % dst_format_desc->block.height == 0);675assert(src_x % src_format_desc->block.width == 0);676assert(src_y % src_format_desc->block.height == 0);677678dst_row = (uint8_t *)dst + dst_y*dst_stride + dst_x*(dst_format_desc->block.bits/8);679src_row = (const uint8_t *)src + src_y*src_stride + src_x*(src_format_desc->block.bits/8);680681/*682* This works because all pixel formats have pixel blocks with power of two683* sizes.684*/685686y_step = MAX2(dst_format_desc->block.height, src_format_desc->block.height);687x_step = MAX2(dst_format_desc->block.width, src_format_desc->block.width);688assert(y_step % dst_format_desc->block.height == 0);689assert(y_step % src_format_desc->block.height == 0);690691dst_step = y_step / dst_format_desc->block.height * dst_stride;692src_step = y_step / src_format_desc->block.height * src_stride;693694/*695* TODO: double formats will loose precision696* TODO: Add a special case for formats that are mere swizzles of each other697*/698699if (src_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS ||700dst_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) {701float *tmp_z = NULL;702uint8_t *tmp_s = NULL;703704assert(x_step == 1);705assert(y_step == 1);706707if (unpack->unpack_z_float && pack->pack_z_float) {708tmp_z = malloc(width * sizeof *tmp_z);709}710711if (unpack->unpack_s_8uint && pack->pack_s_8uint) {712tmp_s = malloc(width * sizeof *tmp_s);713}714715while (height--) {716if (tmp_z) {717util_format_unpack_z_float(src_format, tmp_z, src_row, width);718util_format_pack_z_float(dst_format, dst_row, tmp_z, width);719}720721if (tmp_s) {722util_format_unpack_s_8uint(src_format, tmp_s, src_row, width);723util_format_pack_s_8uint(dst_format, dst_row, tmp_s, width);724}725726dst_row += dst_step;727src_row += src_step;728}729730free(tmp_s);731732free(tmp_z);733734return TRUE;735}736737if (util_format_fits_8unorm(src_format_desc) ||738util_format_fits_8unorm(dst_format_desc)) {739unsigned tmp_stride;740uint8_t *tmp_row;741742if ((!unpack->unpack_rgba_8unorm && !unpack->unpack_rgba_8unorm_rect) ||743!pack->pack_rgba_8unorm) {744return FALSE;745}746747tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;748tmp_row = malloc(y_step * tmp_stride);749if (!tmp_row)750return FALSE;751752while (height >= y_step) {753util_format_unpack_rgba_8unorm_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, y_step);754pack->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);755756dst_row += dst_step;757src_row += src_step;758height -= y_step;759}760761if (height) {762util_format_unpack_rgba_8unorm_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, height);763pack->pack_rgba_8unorm(dst_row, dst_stride, tmp_row, tmp_stride, width, height);764}765766free(tmp_row);767}768else if (util_format_is_pure_sint(src_format) ||769util_format_is_pure_sint(dst_format)) {770unsigned tmp_stride;771int *tmp_row;772773if (util_format_is_pure_sint(src_format) !=774util_format_is_pure_sint(dst_format)) {775return FALSE;776}777778tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;779tmp_row = malloc(y_step * tmp_stride);780if (!tmp_row)781return FALSE;782783while (height >= y_step) {784util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, y_step);785pack->pack_rgba_sint(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);786787dst_row += dst_step;788src_row += src_step;789height -= y_step;790}791792if (height) {793util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, height);794pack->pack_rgba_sint(dst_row, dst_stride, tmp_row, tmp_stride, width, height);795}796797free(tmp_row);798}799else if (util_format_is_pure_uint(src_format) ||800util_format_is_pure_uint(dst_format)) {801unsigned tmp_stride;802unsigned int *tmp_row;803804if ((!unpack->unpack_rgba && !unpack->unpack_rgba_rect) ||805!pack->pack_rgba_uint) {806return FALSE;807}808809tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;810tmp_row = malloc(y_step * tmp_stride);811if (!tmp_row)812return FALSE;813814while (height >= y_step) {815util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, y_step);816pack->pack_rgba_uint(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);817818dst_row += dst_step;819src_row += src_step;820height -= y_step;821}822823if (height) {824util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, height);825pack->pack_rgba_uint(dst_row, dst_stride, tmp_row, tmp_stride, width, height);826}827828free(tmp_row);829}830else {831unsigned tmp_stride;832float *tmp_row;833834if ((!unpack->unpack_rgba && !unpack->unpack_rgba_rect) ||835!pack->pack_rgba_float) {836return FALSE;837}838839tmp_stride = MAX2(width, x_step) * 4 * sizeof *tmp_row;840tmp_row = malloc(y_step * tmp_stride);841if (!tmp_row)842return FALSE;843844while (height >= y_step) {845util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, y_step);846pack->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, y_step);847848dst_row += dst_step;849src_row += src_step;850height -= y_step;851}852853if (height) {854util_format_unpack_rgba_rect(src_format, tmp_row, tmp_stride, src_row, src_stride, width, height);855pack->pack_rgba_float(dst_row, dst_stride, tmp_row, tmp_stride, width, height);856}857858free(tmp_row);859}860return TRUE;861}862863boolean864util_format_translate_3d(enum pipe_format dst_format,865void *dst, unsigned dst_stride,866unsigned dst_slice_stride,867unsigned dst_x, unsigned dst_y,868unsigned dst_z,869enum pipe_format src_format,870const void *src, unsigned src_stride,871unsigned src_slice_stride,872unsigned src_x, unsigned src_y,873unsigned src_z, unsigned width,874unsigned height, unsigned depth)875{876uint8_t *dst_layer;877const uint8_t *src_layer;878unsigned z;879dst_layer = dst;880src_layer = src;881dst_layer += dst_z * dst_slice_stride;882src_layer += src_z * src_slice_stride;883for (z = 0; z < depth; ++z) {884if (!util_format_translate(dst_format, dst_layer, dst_stride,885dst_x, dst_y,886src_format, src_layer, src_stride,887src_x, src_y,888width, height))889return FALSE;890891dst_layer += dst_slice_stride;892src_layer += src_slice_stride;893}894return TRUE;895}896897void util_format_compose_swizzles(const unsigned char swz1[4],898const unsigned char swz2[4],899unsigned char dst[4])900{901unsigned i;902903for (i = 0; i < 4; i++) {904dst[i] = swz2[i] <= PIPE_SWIZZLE_W ?905swz1[swz2[i]] : swz2[i];906}907}908909void util_format_apply_color_swizzle(union pipe_color_union *dst,910const union pipe_color_union *src,911const unsigned char swz[4],912const boolean is_integer)913{914unsigned c;915916if (is_integer) {917for (c = 0; c < 4; ++c) {918switch (swz[c]) {919case PIPE_SWIZZLE_X: dst->ui[c] = src->ui[0]; break;920case PIPE_SWIZZLE_Y: dst->ui[c] = src->ui[1]; break;921case PIPE_SWIZZLE_Z: dst->ui[c] = src->ui[2]; break;922case PIPE_SWIZZLE_W: dst->ui[c] = src->ui[3]; break;923default:924dst->ui[c] = (swz[c] == PIPE_SWIZZLE_1) ? 1 : 0;925break;926}927}928} else {929for (c = 0; c < 4; ++c) {930switch (swz[c]) {931case PIPE_SWIZZLE_X: dst->f[c] = src->f[0]; break;932case PIPE_SWIZZLE_Y: dst->f[c] = src->f[1]; break;933case PIPE_SWIZZLE_Z: dst->f[c] = src->f[2]; break;934case PIPE_SWIZZLE_W: dst->f[c] = src->f[3]; break;935default:936dst->f[c] = (swz[c] == PIPE_SWIZZLE_1) ? 1.0f : 0.0f;937break;938}939}940}941}942943void pipe_swizzle_4f(float *dst, const float *src,944const unsigned char swz[4])945{946unsigned i;947948for (i = 0; i < 4; i++) {949if (swz[i] <= PIPE_SWIZZLE_W)950dst[i] = src[swz[i]];951else if (swz[i] == PIPE_SWIZZLE_0)952dst[i] = 0;953else if (swz[i] == PIPE_SWIZZLE_1)954dst[i] = 1;955}956}957958void util_format_unswizzle_4f(float *dst, const float *src,959const unsigned char swz[4])960{961unsigned i;962963for (i = 0; i < 4; i++) {964switch (swz[i]) {965case PIPE_SWIZZLE_X:966dst[0] = src[i];967break;968case PIPE_SWIZZLE_Y:969dst[1] = src[i];970break;971case PIPE_SWIZZLE_Z:972dst[2] = src[i];973break;974case PIPE_SWIZZLE_W:975dst[3] = src[i];976break;977}978}979}980981enum pipe_format982util_format_snorm8_to_sint8(enum pipe_format format)983{984switch (format) {985case PIPE_FORMAT_R8_SNORM:986return PIPE_FORMAT_R8_SINT;987case PIPE_FORMAT_R8G8_SNORM:988return PIPE_FORMAT_R8G8_SINT;989case PIPE_FORMAT_R8G8B8_SNORM:990return PIPE_FORMAT_R8G8B8_SINT;991case PIPE_FORMAT_R8G8B8A8_SNORM:992return PIPE_FORMAT_R8G8B8A8_SINT;993994case PIPE_FORMAT_A8_SNORM:995return PIPE_FORMAT_A8_SINT;996case PIPE_FORMAT_L8_SNORM:997return PIPE_FORMAT_L8_SINT;998case PIPE_FORMAT_L8A8_SNORM:999return PIPE_FORMAT_L8A8_SINT;1000case PIPE_FORMAT_I8_SNORM:1001return PIPE_FORMAT_I8_SINT;10021003case PIPE_FORMAT_R8G8B8X8_SNORM:1004return PIPE_FORMAT_R8G8B8X8_SINT;1005case PIPE_FORMAT_B8G8R8X8_SNORM:1006return PIPE_FORMAT_B8G8R8X8_SINT;10071008case PIPE_FORMAT_R8A8_SNORM:1009return PIPE_FORMAT_R8A8_SINT;1010case PIPE_FORMAT_G8R8_SNORM:1011return PIPE_FORMAT_G8R8_SINT;10121013case PIPE_FORMAT_A8R8G8B8_SNORM:1014return PIPE_FORMAT_A8R8G8B8_SINT;1015case PIPE_FORMAT_X8R8G8B8_SNORM:1016return PIPE_FORMAT_X8R8G8B8_SINT;10171018case PIPE_FORMAT_A8B8G8R8_SNORM:1019return PIPE_FORMAT_A8B8G8R8_SINT;1020case PIPE_FORMAT_X8B8G8R8_SNORM:1021return PIPE_FORMAT_X8B8G8R8_SINT;10221023case PIPE_FORMAT_R10G10B10A2_SNORM:1024return PIPE_FORMAT_R10G10B10A2_SINT;1025case PIPE_FORMAT_B10G10R10A2_SNORM:1026return PIPE_FORMAT_B10G10R10A2_SINT;10271028default:1029return format;1030}1031}10321033/**1034* If the format is RGB, return BGR. If the format is BGR, return RGB.1035* This may fail by returning PIPE_FORMAT_NONE.1036*/1037enum pipe_format1038util_format_rgb_to_bgr(enum pipe_format format)1039{1040#define REMAP_RGB_ONE(r, rs, g, gs, b, bs, type) \1041case PIPE_FORMAT_##r##rs##g##gs##b##bs##_##type: \1042return PIPE_FORMAT_##b##bs##g##gs##r##rs##_##type;10431044#define REMAP_RGB(rs, gs, bs, type) \1045REMAP_RGB_ONE(R, rs, G, gs, B, bs, type) \1046REMAP_RGB_ONE(B, bs, G, gs, R, rs, type) \10471048#define REMAP_RGBA_ONE(r, rs, g, gs, b, bs, a, as, type) \1049case PIPE_FORMAT_##r##rs##g##gs##b##bs##a##as##_##type: \1050return PIPE_FORMAT_##b##bs##g##gs##r##rs##a##as##_##type;10511052#define REMAP_ARGB_ONE(a, as, r, rs, g, gs, b, bs, type) \1053case PIPE_FORMAT_##a##as##r##rs##g##gs##b##bs##_##type: \1054return PIPE_FORMAT_##a##as##b##bs##g##gs##r##rs##_##type;10551056#define REMAP_RGB_AX(A, rs, gs, bs, as, type) \1057REMAP_RGBA_ONE(R, rs, G, gs, B, bs, A, as, type) \1058REMAP_RGBA_ONE(B, bs, G, gs, R, rs, A, as, type) \10591060#define REMAP_AX_RGB(A, rs, gs, bs, as, type) \1061REMAP_ARGB_ONE(A, as, R, rs, G, gs, B, bs, type) \1062REMAP_ARGB_ONE(A, as, B, bs, G, gs, R, rs, type) \10631064#define REMAP_RGBA(rs, gs, bs, as, type) REMAP_RGB_AX(A, rs, gs, bs, as, type)1065#define REMAP_RGBX(rs, gs, bs, as, type) REMAP_RGB_AX(X, rs, gs, bs, as, type)1066#define REMAP_ARGB(rs, gs, bs, as, type) REMAP_AX_RGB(A, rs, gs, bs, as, type)1067#define REMAP_XRGB(rs, gs, bs, as, type) REMAP_AX_RGB(X, rs, gs, bs, as, type)10681069#define REMAP_RGBA_ALL(rs, gs, bs, as, type) \1070REMAP_RGBA(rs, gs, bs, as, type) \1071REMAP_RGBX(rs, gs, bs, as, type) \1072REMAP_ARGB(rs, gs, bs, as, type) \1073REMAP_XRGB(rs, gs, bs, as, type)10741075switch (format) {1076REMAP_RGB(3, 3, 2, UNORM);1077REMAP_RGB(3, 3, 2, UINT);1078REMAP_RGB(5, 6, 5, SRGB);1079REMAP_RGB(5, 6, 5, UNORM);1080REMAP_RGB(5, 6, 5, UINT);1081REMAP_RGB(8, 8, 8, SRGB);1082REMAP_RGB(8, 8, 8, UNORM);1083REMAP_RGB(8, 8, 8, SNORM);1084REMAP_RGB(8, 8, 8, UINT);1085REMAP_RGB(8, 8, 8, SINT);1086REMAP_RGB(8, 8, 8, USCALED);1087REMAP_RGB(8, 8, 8, SSCALED);10881089/* Complete format sets. */1090REMAP_RGBA_ALL(5, 5, 5, 1, UNORM);1091REMAP_RGBA_ALL(8, 8, 8, 8, SRGB);1092REMAP_RGBA_ALL(8, 8, 8, 8, UNORM);1093REMAP_RGBA_ALL(8, 8, 8, 8, SNORM);1094REMAP_RGBA_ALL(8, 8, 8, 8, SINT);10951096/* Format sets missing XRGB/XBGR. */1097REMAP_RGBA(4, 4, 4, 4, UNORM);1098REMAP_RGBX(4, 4, 4, 4, UNORM);1099REMAP_ARGB(4, 4, 4, 4, UNORM);11001101REMAP_RGBA(8, 8, 8, 8, UINT);1102REMAP_RGBX(8, 8, 8, 8, UINT);1103REMAP_ARGB(8, 8, 8, 8, UINT);11041105REMAP_RGBA(10, 10, 10, 2, UNORM);1106REMAP_RGBX(10, 10, 10, 2, UNORM);1107REMAP_ARGB(10, 10, 10, 2, UNORM);11081109/* Format sets missing a half of combinations. */1110REMAP_RGBA(4, 4, 4, 4, UINT);1111REMAP_ARGB(4, 4, 4, 4, UINT);11121113REMAP_RGBA(5, 5, 5, 1, UINT);1114REMAP_ARGB(5, 5, 5, 1, UINT);11151116REMAP_RGBA(10, 10, 10, 2, SNORM);1117REMAP_RGBX(10, 10, 10, 2, SNORM);11181119REMAP_RGBA(10, 10, 10, 2, UINT);1120REMAP_ARGB(10, 10, 10, 2, UINT);11211122/* Format sets having only RGBA/BGRA. */1123REMAP_RGBA(8, 8, 8, 8, USCALED);1124REMAP_RGBA(8, 8, 8, 8, SSCALED);1125REMAP_RGBA(10, 10, 10, 2, SINT);1126REMAP_RGBA(10, 10, 10, 2, USCALED);1127REMAP_RGBA(10, 10, 10, 2, SSCALED);11281129default:1130return PIPE_FORMAT_NONE;1131}1132}11331134static const struct util_format_unpack_description *util_format_unpack_table[PIPE_FORMAT_COUNT];11351136static void1137util_format_unpack_table_init(void)1138{1139for (enum pipe_format format = PIPE_FORMAT_NONE; format < PIPE_FORMAT_COUNT; format++) {1140#if (defined(PIPE_ARCH_AARCH64) || defined(PIPE_ARCH_ARM)) && !defined NO_FORMAT_ASM1141const struct util_format_unpack_description *unpack = util_format_unpack_description_neon(format);1142if (unpack) {1143util_format_unpack_table[format] = unpack;1144continue;1145}1146#endif11471148util_format_unpack_table[format] = util_format_unpack_description_generic(format);1149}1150}11511152const struct util_format_unpack_description *1153util_format_unpack_description(enum pipe_format format)1154{1155static once_flag flag = ONCE_FLAG_INIT;1156call_once(&flag, util_format_unpack_table_init);11571158return util_format_unpack_table[format];1159}116011611162