/* * Copyright (c) 2012-2013 Etnaviv Project * * 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 * 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. */ /* inlined translation functions between gallium and vivante */ #ifndef H_TRANSLATE #define H_TRANSLATE #include "pipe/p_defines.h" #include "pipe/p_format.h" #include "pipe/p_state.h" #include "etnaviv_debug.h" #include "etnaviv_format.h" #include "etnaviv_tiling.h" #include "etnaviv_util.h" #include "hw/cmdstream.xml.h" #include "hw/state.xml.h" #include "hw/state_3d.xml.h" #include "util/u_format.h" #include /* Returned when there is no match of pipe value to etna value */ #define ETNA_NO_MATCH (~0) static inline uint32_t translate_cull_face(unsigned cull_face, unsigned front_ccw) { switch (cull_face) { case PIPE_FACE_NONE: return VIVS_PA_CONFIG_CULL_FACE_MODE_OFF; case PIPE_FACE_BACK: return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CW : VIVS_PA_CONFIG_CULL_FACE_MODE_CCW; case PIPE_FACE_FRONT: return front_ccw ? VIVS_PA_CONFIG_CULL_FACE_MODE_CCW : VIVS_PA_CONFIG_CULL_FACE_MODE_CW; default: DBG("Unhandled cull face mode %i", cull_face); return ETNA_NO_MATCH; } } static inline uint32_t translate_polygon_mode(unsigned polygon_mode) { switch (polygon_mode) { case PIPE_POLYGON_MODE_FILL: return VIVS_PA_CONFIG_FILL_MODE_SOLID; case PIPE_POLYGON_MODE_LINE: return VIVS_PA_CONFIG_FILL_MODE_WIREFRAME; case PIPE_POLYGON_MODE_POINT: return VIVS_PA_CONFIG_FILL_MODE_POINT; default: DBG("Unhandled polygon mode %i", polygon_mode); return ETNA_NO_MATCH; } } static inline uint32_t translate_stencil_mode(bool enable_0, bool enable_1) { if (enable_0) { return enable_1 ? VIVS_PE_STENCIL_CONFIG_MODE_TWO_SIDED : VIVS_PE_STENCIL_CONFIG_MODE_ONE_SIDED; } else { return VIVS_PE_STENCIL_CONFIG_MODE_DISABLED; } } static inline uint32_t translate_stencil_op(unsigned stencil_op) { switch (stencil_op) { case PIPE_STENCIL_OP_KEEP: return STENCIL_OP_KEEP; case PIPE_STENCIL_OP_ZERO: return STENCIL_OP_ZERO; case PIPE_STENCIL_OP_REPLACE: return STENCIL_OP_REPLACE; case PIPE_STENCIL_OP_INCR: return STENCIL_OP_INCR; case PIPE_STENCIL_OP_DECR: return STENCIL_OP_DECR; case PIPE_STENCIL_OP_INCR_WRAP: return STENCIL_OP_INCR_WRAP; case PIPE_STENCIL_OP_DECR_WRAP: return STENCIL_OP_DECR_WRAP; case PIPE_STENCIL_OP_INVERT: return STENCIL_OP_INVERT; default: DBG("Unhandled stencil op: %i", stencil_op); return ETNA_NO_MATCH; } } static inline uint32_t translate_blend(unsigned blend) { switch (blend) { case PIPE_BLEND_ADD: return BLEND_EQ_ADD; case PIPE_BLEND_SUBTRACT: return BLEND_EQ_SUBTRACT; case PIPE_BLEND_REVERSE_SUBTRACT: return BLEND_EQ_REVERSE_SUBTRACT; case PIPE_BLEND_MIN: return BLEND_EQ_MIN; case PIPE_BLEND_MAX: return BLEND_EQ_MAX; default: DBG("Unhandled blend: %i", blend); return ETNA_NO_MATCH; } } static inline uint32_t translate_blend_factor(unsigned blend_factor) { switch (blend_factor) { case PIPE_BLENDFACTOR_ONE: return BLEND_FUNC_ONE; case PIPE_BLENDFACTOR_SRC_COLOR: return BLEND_FUNC_SRC_COLOR; case PIPE_BLENDFACTOR_SRC_ALPHA: return BLEND_FUNC_SRC_ALPHA; case PIPE_BLENDFACTOR_DST_ALPHA: return BLEND_FUNC_DST_ALPHA; case PIPE_BLENDFACTOR_DST_COLOR: return BLEND_FUNC_DST_COLOR; case PIPE_BLENDFACTOR_SRC_ALPHA_SATURATE: return BLEND_FUNC_SRC_ALPHA_SATURATE; case PIPE_BLENDFACTOR_CONST_COLOR: return BLEND_FUNC_CONSTANT_COLOR; case PIPE_BLENDFACTOR_CONST_ALPHA: return BLEND_FUNC_CONSTANT_ALPHA; case PIPE_BLENDFACTOR_ZERO: return BLEND_FUNC_ZERO; case PIPE_BLENDFACTOR_INV_SRC_COLOR: return BLEND_FUNC_ONE_MINUS_SRC_COLOR; case PIPE_BLENDFACTOR_INV_SRC_ALPHA: return BLEND_FUNC_ONE_MINUS_SRC_ALPHA; case PIPE_BLENDFACTOR_INV_DST_ALPHA: return BLEND_FUNC_ONE_MINUS_DST_ALPHA; case PIPE_BLENDFACTOR_INV_DST_COLOR: return BLEND_FUNC_ONE_MINUS_DST_COLOR; case PIPE_BLENDFACTOR_INV_CONST_COLOR: return BLEND_FUNC_ONE_MINUS_CONSTANT_COLOR; case PIPE_BLENDFACTOR_INV_CONST_ALPHA: return BLEND_FUNC_ONE_MINUS_CONSTANT_ALPHA; case PIPE_BLENDFACTOR_SRC1_COLOR: case PIPE_BLENDFACTOR_SRC1_ALPHA: case PIPE_BLENDFACTOR_INV_SRC1_COLOR: case PIPE_BLENDFACTOR_INV_SRC1_ALPHA: default: DBG("Unhandled blend factor: %i", blend_factor); return ETNA_NO_MATCH; } } static inline uint32_t translate_texture_wrapmode(unsigned wrap) { switch (wrap) { case PIPE_TEX_WRAP_REPEAT: return TEXTURE_WRAPMODE_REPEAT; case PIPE_TEX_WRAP_CLAMP: return TEXTURE_WRAPMODE_CLAMP_TO_EDGE; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return TEXTURE_WRAPMODE_CLAMP_TO_EDGE; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return TEXTURE_WRAPMODE_CLAMP_TO_EDGE; /* XXX */ case PIPE_TEX_WRAP_MIRROR_REPEAT: return TEXTURE_WRAPMODE_MIRRORED_REPEAT; case PIPE_TEX_WRAP_MIRROR_CLAMP: return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */ case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */ case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: return TEXTURE_WRAPMODE_MIRRORED_REPEAT; /* XXX */ default: DBG("Unhandled texture wrapmode: %i", wrap); return ETNA_NO_MATCH; } } static inline uint32_t translate_texture_mipfilter(unsigned filter) { switch (filter) { case PIPE_TEX_MIPFILTER_NEAREST: return TEXTURE_FILTER_NEAREST; case PIPE_TEX_MIPFILTER_LINEAR: return TEXTURE_FILTER_LINEAR; case PIPE_TEX_MIPFILTER_NONE: return TEXTURE_FILTER_NONE; default: DBG("Unhandled texture mipfilter: %i", filter); return ETNA_NO_MATCH; } } static inline uint32_t translate_texture_filter(unsigned filter) { switch (filter) { case PIPE_TEX_FILTER_NEAREST: return TEXTURE_FILTER_NEAREST; case PIPE_TEX_FILTER_LINEAR: return TEXTURE_FILTER_LINEAR; /* What about anisotropic? */ default: DBG("Unhandled texture filter: %i", filter); return ETNA_NO_MATCH; } } /* return a RS "compatible" format for use when copying */ static inline enum pipe_format etna_compatible_rs_format(enum pipe_format fmt) { /* YUYV and UYVY are blocksize 4, but 2 bytes per pixel */ if (fmt == PIPE_FORMAT_YUYV || fmt == PIPE_FORMAT_UYVY) return PIPE_FORMAT_B4G4R4A4_UNORM; switch (util_format_get_blocksize(fmt)) { case 2: return PIPE_FORMAT_B4G4R4A4_UNORM; case 4: return PIPE_FORMAT_B8G8R8A8_UNORM; default: return fmt; } } static inline int translate_rb_src_dst_swap(enum pipe_format src, enum pipe_format dst) { return translate_rs_format_rb_swap(src) ^ translate_rs_format_rb_swap(dst); } static inline uint32_t translate_depth_format(enum pipe_format fmt) { /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */ switch (fmt) { case PIPE_FORMAT_Z16_UNORM: return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D16; case PIPE_FORMAT_X8Z24_UNORM: return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8; case PIPE_FORMAT_S8_UINT_Z24_UNORM: return VIVS_PE_DEPTH_CONFIG_DEPTH_FORMAT_D24S8; default: return ETNA_NO_MATCH; } } /* render target format for MSAA */ static inline uint32_t translate_msaa_format(enum pipe_format fmt) { /* Note: Pipe format convention is LSB to MSB, VIVS is MSB to LSB */ switch (fmt) { case PIPE_FORMAT_B4G4R4X4_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4; case PIPE_FORMAT_B4G4R4A4_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A4R4G4B4; case PIPE_FORMAT_B5G5R5X1_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5; case PIPE_FORMAT_B5G5R5A1_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A1R5G5B5; case PIPE_FORMAT_B5G6R5_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_R5G6B5; case PIPE_FORMAT_B8G8R8X8_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_X8R8G8B8; case PIPE_FORMAT_B8G8R8A8_UNORM: return VIVS_TS_MEM_CONFIG_MSAA_FORMAT_A8R8G8B8; /* MSAA with YUYV not supported */ default: return ETNA_NO_MATCH; } } /* Return normalization flag for vertex element format */ static inline uint32_t translate_vertex_format_normalize(enum pipe_format fmt) { const struct util_format_description *desc = util_format_description(fmt); if (!desc) return VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF; /* assumes that normalization of channel 0 holds for all channels; * this holds for all vertex formats that we support */ return desc->channel[0].normalized ? VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_ON : VIVS_FE_VERTEX_ELEMENT_CONFIG_NORMALIZE_OFF; } static inline uint32_t translate_index_size(unsigned index_size) { switch (index_size) { case 1: return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_CHAR; case 2: return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_SHORT; case 4: return VIVS_FE_INDEX_STREAM_CONTROL_TYPE_UNSIGNED_INT; default: DBG("Unhandled index size %i", index_size); return ETNA_NO_MATCH; } } static inline uint32_t translate_draw_mode(unsigned mode) { switch (mode) { case PIPE_PRIM_POINTS: return PRIMITIVE_TYPE_POINTS; case PIPE_PRIM_LINES: return PRIMITIVE_TYPE_LINES; case PIPE_PRIM_LINE_LOOP: return PRIMITIVE_TYPE_LINE_LOOP; case PIPE_PRIM_LINE_STRIP: return PRIMITIVE_TYPE_LINE_STRIP; case PIPE_PRIM_TRIANGLES: return PRIMITIVE_TYPE_TRIANGLES; case PIPE_PRIM_TRIANGLE_STRIP: return PRIMITIVE_TYPE_TRIANGLE_STRIP; case PIPE_PRIM_TRIANGLE_FAN: return PRIMITIVE_TYPE_TRIANGLE_FAN; case PIPE_PRIM_QUADS: return PRIMITIVE_TYPE_QUADS; default: DBG("Unhandled draw mode primitive %i", mode); return ETNA_NO_MATCH; } } /* Get size multiple for size of texture/rendertarget with a certain layout * This is affected by many different parameters: * - A horizontal multiple of 16 is used when possible as resolve can be used * at the cost of only a little bit extra memory usage. * - If the surface is to be used with the resolve engine, set rs_align true. * If set, a horizontal multiple of 16 will be used for tiled and linear, * otherwise one of 16. However, such a surface will be incompatible * with the samplers if the GPU does hot support the HALIGN feature. * - If the surface is supertiled, horizontal and vertical multiple is always 64 * - If the surface is multi tiled or supertiled, make sure that the vertical size * is a multiple of the number of pixel pipes as well. * */ static inline void etna_layout_multiple(unsigned layout, unsigned pixel_pipes, bool rs_align, unsigned *paddingX, unsigned *paddingY, unsigned *halign) { switch (layout) { case ETNA_LAYOUT_LINEAR: *paddingX = rs_align ? 16 : 4; *paddingY = 1; *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR; break; case ETNA_LAYOUT_TILED: *paddingX = rs_align ? 16 : 4; *paddingY = 4; *halign = rs_align ? TEXTURE_HALIGN_SIXTEEN : TEXTURE_HALIGN_FOUR; break; case ETNA_LAYOUT_SUPER_TILED: *paddingX = 64; *paddingY = 64; *halign = TEXTURE_HALIGN_SUPER_TILED; break; case ETNA_LAYOUT_MULTI_TILED: *paddingX = 16; *paddingY = 4 * pixel_pipes; *halign = TEXTURE_HALIGN_SPLIT_TILED; break; case ETNA_LAYOUT_MULTI_SUPERTILED: *paddingX = 64; *paddingY = 64 * pixel_pipes; *halign = TEXTURE_HALIGN_SPLIT_SUPER_TILED; break; default: DBG("Unhandled layout %i", layout); } } static inline uint32_t translate_clear_depth_stencil(enum pipe_format format, float depth, unsigned stencil) { uint32_t clear_value = 0; // XXX util_pack_color switch (format) { case PIPE_FORMAT_Z16_UNORM: clear_value = etna_cfloat_to_uintN(depth, 16); clear_value |= clear_value << 16; break; case PIPE_FORMAT_X8Z24_UNORM: case PIPE_FORMAT_S8_UINT_Z24_UNORM: clear_value = (etna_cfloat_to_uintN(depth, 24) << 8) | (stencil & 0xFF); break; default: DBG("Unhandled pipe format for depth stencil clear: %i", format); } return clear_value; } /* Convert MSAA number of samples to x and y scaling factor and * VIVS_GL_MULTI_SAMPLE_CONFIG value. * Return true if supported and false otherwise. */ static inline bool translate_samples_to_xyscale(int num_samples, int *xscale_out, int *yscale_out, uint32_t *config_out) { int xscale, yscale; uint32_t config; switch (num_samples) { case 0: case 1: xscale = 1; yscale = 1; config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_NONE; break; case 2: xscale = 2; yscale = 1; config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_2X; break; case 4: xscale = 2; yscale = 2; config = VIVS_GL_MULTI_SAMPLE_CONFIG_MSAA_SAMPLES_4X; break; default: return false; } if (xscale_out) *xscale_out = xscale; if (yscale_out) *yscale_out = yscale; if (config_out) *config_out = config; return true; } #endif