/*
* 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/common_3d.xml.h"
#include "hw/state.xml.h"
#include "hw/state_3d.xml.h"
#include "util/u_format.h"
#include "util/u_math.h"
#include <stdio.h>
/* 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 COLOR_COMPRESSION_FORMAT_A4R4G4B4;
case PIPE_FORMAT_B4G4R4A4_UNORM:
return COLOR_COMPRESSION_FORMAT_A4R4G4B4;
case PIPE_FORMAT_B5G5R5X1_UNORM:
return COLOR_COMPRESSION_FORMAT_A1R5G5B5;
case PIPE_FORMAT_B5G5R5A1_UNORM:
return COLOR_COMPRESSION_FORMAT_A1R5G5B5;
case PIPE_FORMAT_B5G6R5_UNORM:
return COLOR_COMPRESSION_FORMAT_R5G6B5;
case PIPE_FORMAT_B8G8R8X8_UNORM:
return COLOR_COMPRESSION_FORMAT_X8R8G8B8;
case PIPE_FORMAT_B8G8R8A8_UNORM:
return COLOR_COMPRESSION_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 void etna_adjust_rs_align(unsigned num_pixelpipes,
unsigned *paddingX, unsigned *paddingY)
{
unsigned alignX = ETNA_RS_WIDTH_MASK + 1;
unsigned alignY = (ETNA_RS_HEIGHT_MASK + 1) * num_pixelpipes;
if (paddingX)
*paddingX = align(*paddingX, alignX);
if (paddingY)
*paddingY = align(*paddingY, alignY);
}
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