Files
xf86-video-ati/src/evergreen_exa.c
Enrico Weigelt, metux IT consult fff6cf2b4b replace PICT_b8g8r8a8 by PIXMAN_b8g8r8a8
Try not to use old compat macros anymore, use the real ones instead.

Signed-off-by: Enrico Weigelt, metux IT consult <info@metux.net>
2025-08-07 13:35:47 +02:00

2134 lines
66 KiB
C

/*
* Copyright 2010 Advanced Micro Devices, Inc.
*
* 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.
*
* Author: Alex Deucher <alexander.deucher@amd.com>
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "xf86.h"
#include "exa.h"
#include "radeon.h"
#include "radeon_reg.h"
#include "evergreen_shader.h"
#include "evergreen_reg.h"
#include "evergreen_state.h"
#include "radeon_exa_shared.h"
#include "radeon_vbo.h"
extern int cayman_solid_vs(RADEONChipFamily ChipSet, uint32_t* vs);
extern int cayman_solid_ps(RADEONChipFamily ChipSet, uint32_t* ps);
extern int cayman_copy_vs(RADEONChipFamily ChipSet, uint32_t* vs);
extern int cayman_copy_ps(RADEONChipFamily ChipSet, uint32_t* ps);
extern int cayman_xv_vs(RADEONChipFamily ChipSet, uint32_t* shader);
extern int cayman_xv_ps(RADEONChipFamily ChipSet, uint32_t* shader);
extern int cayman_comp_vs(RADEONChipFamily ChipSet, uint32_t* vs);
extern int cayman_comp_ps(RADEONChipFamily ChipSet, uint32_t* ps);
static Bool
EVERGREENPrepareSolid(PixmapPtr pPix, int alu, Pixel pm, Pixel fg)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
cb_config_t cb_conf;
shader_config_t vs_conf, ps_conf;
uint32_t a, r, g, b;
float *ps_alu_consts;
const_config_t ps_const_conf;
struct r600_accel_object dst;
if (!RADEONCheckBPP(pPix->drawable.bitsPerPixel))
RADEON_FALLBACK(("EVERGREENCheckDatatype failed\n"));
if (!RADEONValidPM(pm, pPix->drawable.bitsPerPixel))
RADEON_FALLBACK(("invalid planemask\n"));
dst.bo = radeon_get_pixmap_bo(pPix)->bo.radeon;
dst.tiling_flags = radeon_get_pixmap_tiling(pPix);
dst.surface = radeon_get_pixmap_surface(pPix);
dst.pitch = exaGetPixmapPitch(pPix) / (pPix->drawable.bitsPerPixel / 8);
dst.width = pPix->drawable.width;
dst.height = pPix->drawable.height;
dst.bpp = pPix->drawable.bitsPerPixel;
dst.domain = RADEON_GEM_DOMAIN_VRAM;
if (!R600SetAccelState(pScrn,
NULL,
NULL,
&dst,
accel_state->solid_vs_offset, accel_state->solid_ps_offset,
alu, pm))
return FALSE;
CLEAR (cb_conf);
CLEAR (vs_conf);
CLEAR (ps_conf);
CLEAR (ps_const_conf);
radeon_vbo_check(pScrn, &accel_state->vbo, 16);
radeon_vbo_check(pScrn, &accel_state->cbuf, 256);
radeon_cp_start(pScrn);
evergreen_set_default_state(pScrn);
evergreen_set_generic_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_screen_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_window_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
/* Shader */
vs_conf.shader_addr = accel_state->vs_mc_addr;
vs_conf.shader_size = accel_state->vs_size;
vs_conf.num_gprs = 2;
vs_conf.stack_size = 0;
vs_conf.bo = accel_state->shaders_bo;
evergreen_vs_setup(pScrn, &vs_conf, RADEON_GEM_DOMAIN_VRAM);
ps_conf.shader_addr = accel_state->ps_mc_addr;
ps_conf.shader_size = accel_state->ps_size;
ps_conf.num_gprs = 1;
ps_conf.stack_size = 0;
ps_conf.clamp_consts = 0;
ps_conf.export_mode = 2;
ps_conf.bo = accel_state->shaders_bo;
evergreen_ps_setup(pScrn, &ps_conf, RADEON_GEM_DOMAIN_VRAM);
cb_conf.id = 0;
cb_conf.w = accel_state->dst_obj.pitch;
cb_conf.h = accel_state->dst_obj.height;
cb_conf.base = 0;
cb_conf.bo = accel_state->dst_obj.bo;
cb_conf.surface = accel_state->dst_obj.surface;
if (accel_state->dst_obj.bpp == 8) {
cb_conf.format = COLOR_8;
cb_conf.comp_swap = 3; /* A */
} else if (accel_state->dst_obj.bpp == 16) {
cb_conf.format = COLOR_5_6_5;
cb_conf.comp_swap = 2; /* RGB */
#if X_BYTE_ORDER == X_BIG_ENDIAN
cb_conf.endian = ENDIAN_8IN16;
#endif
} else {
cb_conf.format = COLOR_8_8_8_8;
cb_conf.comp_swap = 1; /* ARGB */
#if X_BYTE_ORDER == X_BIG_ENDIAN
cb_conf.endian = ENDIAN_8IN32;
#endif
}
cb_conf.source_format = EXPORT_4C_16BPC;
cb_conf.blend_clamp = 1;
/* Render setup */
if (accel_state->planemask & 0x000000ff)
cb_conf.pmask |= 4; /* B */
if (accel_state->planemask & 0x0000ff00)
cb_conf.pmask |= 2; /* G */
if (accel_state->planemask & 0x00ff0000)
cb_conf.pmask |= 1; /* R */
if (accel_state->planemask & 0xff000000)
cb_conf.pmask |= 8; /* A */
cb_conf.rop = accel_state->rop;
if ((accel_state->dst_obj.tiling_flags & RADEON_TILING_MASK) ==
RADEON_TILING_LINEAR) {
cb_conf.array_mode = 0;
cb_conf.non_disp_tiling = 1;
}
evergreen_set_render_target(pScrn, &cb_conf, accel_state->dst_obj.domain);
evergreen_set_spi(pScrn, 0, 0);
/* PS alu constants */
ps_const_conf.size_bytes = 256;
ps_const_conf.type = SHADER_TYPE_PS;
ps_alu_consts = radeon_vbo_space(pScrn, &accel_state->cbuf, 256);
ps_const_conf.bo = accel_state->cbuf.vb_bo;
ps_const_conf.const_addr = accel_state->cbuf.vb_offset;
ps_const_conf.cpu_ptr = (uint32_t *)(char *)ps_alu_consts;
if (accel_state->dst_obj.bpp == 16) {
r = (fg >> 11) & 0x1f;
g = (fg >> 5) & 0x3f;
b = (fg >> 0) & 0x1f;
ps_alu_consts[0] = (float)r / 31; /* R */
ps_alu_consts[1] = (float)g / 63; /* G */
ps_alu_consts[2] = (float)b / 31; /* B */
ps_alu_consts[3] = 1.0; /* A */
} else if (accel_state->dst_obj.bpp == 8) {
a = (fg >> 0) & 0xff;
ps_alu_consts[0] = 0.0; /* R */
ps_alu_consts[1] = 0.0; /* G */
ps_alu_consts[2] = 0.0; /* B */
ps_alu_consts[3] = (float)a / 255; /* A */
} else {
a = (fg >> 24) & 0xff;
r = (fg >> 16) & 0xff;
g = (fg >> 8) & 0xff;
b = (fg >> 0) & 0xff;
ps_alu_consts[0] = (float)r / 255; /* R */
ps_alu_consts[1] = (float)g / 255; /* G */
ps_alu_consts[2] = (float)b / 255; /* B */
ps_alu_consts[3] = (float)a / 255; /* A */
}
radeon_vbo_commit(pScrn, &accel_state->cbuf);
evergreen_set_alu_consts(pScrn, &ps_const_conf, RADEON_GEM_DOMAIN_GTT);
if (accel_state->vsync)
RADEONVlineHelperClear(pScrn);
accel_state->dst_pix = pPix;
accel_state->fg = fg;
return TRUE;
}
static void
EVERGREENDoneSolid(PixmapPtr pPix)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
if (accel_state->vsync)
evergreen_cp_wait_vline_sync(pScrn, pPix,
accel_state->vline_crtc,
accel_state->vline_y1,
accel_state->vline_y2);
evergreen_finish_op(pScrn, 8);
}
static void
EVERGREENSolid(PixmapPtr pPix, int x1, int y1, int x2, int y2)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
float *vb;
if (CS_FULL(info->cs)) {
EVERGREENDoneSolid(info->accel_state->dst_pix);
radeon_cs_flush_indirect(pScrn);
EVERGREENPrepareSolid(accel_state->dst_pix,
accel_state->rop,
accel_state->planemask,
accel_state->fg);
}
if (accel_state->vsync)
RADEONVlineHelperSet(pScrn, x1, y1, x2, y2);
vb = radeon_vbo_space(pScrn, &accel_state->vbo, 8);
vb[0] = (float)x1;
vb[1] = (float)y1;
vb[2] = (float)x1;
vb[3] = (float)y2;
vb[4] = (float)x2;
vb[5] = (float)y2;
radeon_vbo_commit(pScrn, &accel_state->vbo);
}
static void
EVERGREENDoPrepareCopy(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
cb_config_t cb_conf;
tex_resource_t tex_res;
tex_sampler_t tex_samp;
shader_config_t vs_conf, ps_conf;
CLEAR (cb_conf);
CLEAR (tex_res);
CLEAR (tex_samp);
CLEAR (vs_conf);
CLEAR (ps_conf);
radeon_vbo_check(pScrn, &accel_state->vbo, 16);
radeon_cp_start(pScrn);
evergreen_set_default_state(pScrn);
evergreen_set_generic_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_screen_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_window_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
/* Shader */
vs_conf.shader_addr = accel_state->vs_mc_addr;
vs_conf.shader_size = accel_state->vs_size;
vs_conf.num_gprs = 2;
vs_conf.stack_size = 0;
vs_conf.bo = accel_state->shaders_bo;
evergreen_vs_setup(pScrn, &vs_conf, RADEON_GEM_DOMAIN_VRAM);
ps_conf.shader_addr = accel_state->ps_mc_addr;
ps_conf.shader_size = accel_state->ps_size;
ps_conf.num_gprs = 1;
ps_conf.stack_size = 0;
ps_conf.clamp_consts = 0;
ps_conf.export_mode = 2;
ps_conf.bo = accel_state->shaders_bo;
evergreen_ps_setup(pScrn, &ps_conf, RADEON_GEM_DOMAIN_VRAM);
/* Texture */
tex_res.id = 0;
tex_res.w = accel_state->src_obj[0].width;
tex_res.h = accel_state->src_obj[0].height;
tex_res.pitch = accel_state->src_obj[0].pitch;
tex_res.depth = 0;
tex_res.dim = SQ_TEX_DIM_2D;
tex_res.base = 0;
tex_res.mip_base = 0;
tex_res.size = accel_state->src_size[0];
tex_res.bo = accel_state->src_obj[0].bo;
tex_res.mip_bo = accel_state->src_obj[0].bo;
tex_res.surface = accel_state->src_obj[0].surface;
if (accel_state->src_obj[0].bpp == 8) {
tex_res.format = FMT_8;
tex_res.dst_sel_x = SQ_SEL_1; /* R */
tex_res.dst_sel_y = SQ_SEL_1; /* G */
tex_res.dst_sel_z = SQ_SEL_1; /* B */
tex_res.dst_sel_w = SQ_SEL_X; /* A */
} else if (accel_state->src_obj[0].bpp == 16) {
tex_res.format = FMT_5_6_5;
tex_res.dst_sel_x = SQ_SEL_Z; /* R */
tex_res.dst_sel_y = SQ_SEL_Y; /* G */
tex_res.dst_sel_z = SQ_SEL_X; /* B */
tex_res.dst_sel_w = SQ_SEL_1; /* A */
} else {
tex_res.format = FMT_8_8_8_8;
tex_res.dst_sel_x = SQ_SEL_Z; /* R */
tex_res.dst_sel_y = SQ_SEL_Y; /* G */
tex_res.dst_sel_z = SQ_SEL_X; /* B */
tex_res.dst_sel_w = SQ_SEL_W; /* A */
}
tex_res.base_level = 0;
tex_res.last_level = 0;
tex_res.perf_modulation = 0;
if ((accel_state->src_obj[0].tiling_flags & RADEON_TILING_MASK) ==
RADEON_TILING_LINEAR)
tex_res.array_mode = 0;
evergreen_set_tex_resource(pScrn, &tex_res, accel_state->src_obj[0].domain);
tex_samp.id = 0;
tex_samp.clamp_x = SQ_TEX_CLAMP_LAST_TEXEL;
tex_samp.clamp_y = SQ_TEX_CLAMP_LAST_TEXEL;
tex_samp.clamp_z = SQ_TEX_WRAP;
tex_samp.xy_mag_filter = SQ_TEX_XY_FILTER_POINT;
tex_samp.xy_min_filter = SQ_TEX_XY_FILTER_POINT;
tex_samp.mc_coord_truncate = 1;
tex_samp.z_filter = SQ_TEX_Z_FILTER_NONE;
tex_samp.mip_filter = 0; /* no mipmap */
evergreen_set_tex_sampler (pScrn, &tex_samp);
cb_conf.id = 0;
cb_conf.w = accel_state->dst_obj.pitch;
cb_conf.h = accel_state->dst_obj.height;
cb_conf.base = 0;
cb_conf.bo = accel_state->dst_obj.bo;
cb_conf.surface = accel_state->dst_obj.surface;
if (accel_state->dst_obj.bpp == 8) {
cb_conf.format = COLOR_8;
cb_conf.comp_swap = 3; /* A */
} else if (accel_state->dst_obj.bpp == 16) {
cb_conf.format = COLOR_5_6_5;
cb_conf.comp_swap = 2; /* RGB */
} else {
cb_conf.format = COLOR_8_8_8_8;
cb_conf.comp_swap = 1; /* ARGB */
}
cb_conf.source_format = EXPORT_4C_16BPC;
cb_conf.blend_clamp = 1;
/* Render setup */
if (accel_state->planemask & 0x000000ff)
cb_conf.pmask |= 4; /* B */
if (accel_state->planemask & 0x0000ff00)
cb_conf.pmask |= 2; /* G */
if (accel_state->planemask & 0x00ff0000)
cb_conf.pmask |= 1; /* R */
if (accel_state->planemask & 0xff000000)
cb_conf.pmask |= 8; /* A */
cb_conf.rop = accel_state->rop;
if ((accel_state->dst_obj.tiling_flags & RADEON_TILING_MASK) ==
RADEON_TILING_LINEAR) {
cb_conf.array_mode = 0;
cb_conf.non_disp_tiling = 1;
}
evergreen_set_render_target(pScrn, &cb_conf, accel_state->dst_obj.domain);
evergreen_set_spi(pScrn, (1 - 1), 1);
}
static void
EVERGREENDoCopy(ScrnInfoPtr pScrn)
{
evergreen_finish_op(pScrn, 16);
}
static void
EVERGREENDoCopyVline(PixmapPtr pPix)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
if (accel_state->vsync)
evergreen_cp_wait_vline_sync(pScrn, pPix,
accel_state->vline_crtc,
accel_state->vline_y1,
accel_state->vline_y2);
evergreen_finish_op(pScrn, 16);
}
static void
EVERGREENAppendCopyVertex(ScrnInfoPtr pScrn,
int srcX, int srcY,
int dstX, int dstY,
int w, int h)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
float *vb;
vb = radeon_vbo_space(pScrn, &accel_state->vbo, 16);
vb[0] = (float)dstX;
vb[1] = (float)dstY;
vb[2] = (float)srcX;
vb[3] = (float)srcY;
vb[4] = (float)dstX;
vb[5] = (float)(dstY + h);
vb[6] = (float)srcX;
vb[7] = (float)(srcY + h);
vb[8] = (float)(dstX + w);
vb[9] = (float)(dstY + h);
vb[10] = (float)(srcX + w);
vb[11] = (float)(srcY + h);
radeon_vbo_commit(pScrn, &accel_state->vbo);
}
static Bool
EVERGREENPrepareCopy(PixmapPtr pSrc, PixmapPtr pDst,
int xdir, int ydir,
int rop,
Pixel planemask)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
struct r600_accel_object src_obj, dst_obj;
if (!RADEONCheckBPP(pSrc->drawable.bitsPerPixel))
RADEON_FALLBACK(("EVERGREENCheckDatatype src failed\n"));
if (!RADEONCheckBPP(pDst->drawable.bitsPerPixel))
RADEON_FALLBACK(("EVERGREENCheckDatatype dst failed\n"));
if (!RADEONValidPM(planemask, pDst->drawable.bitsPerPixel))
RADEON_FALLBACK(("Invalid planemask\n"));
dst_obj.pitch = exaGetPixmapPitch(pDst) / (pDst->drawable.bitsPerPixel / 8);
src_obj.pitch = exaGetPixmapPitch(pSrc) / (pSrc->drawable.bitsPerPixel / 8);
accel_state->same_surface = FALSE;
src_obj.bo = radeon_get_pixmap_bo(pSrc)->bo.radeon;
dst_obj.bo = radeon_get_pixmap_bo(pDst)->bo.radeon;
dst_obj.surface = radeon_get_pixmap_surface(pDst);
src_obj.surface = radeon_get_pixmap_surface(pSrc);
dst_obj.tiling_flags = radeon_get_pixmap_tiling(pDst);
src_obj.tiling_flags = radeon_get_pixmap_tiling(pSrc);
if (src_obj.bo == dst_obj.bo)
accel_state->same_surface = TRUE;
src_obj.width = pSrc->drawable.width;
src_obj.height = pSrc->drawable.height;
src_obj.bpp = pSrc->drawable.bitsPerPixel;
src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT;
dst_obj.width = pDst->drawable.width;
dst_obj.height = pDst->drawable.height;
dst_obj.bpp = pDst->drawable.bitsPerPixel;
if (radeon_get_pixmap_shared(pDst) == TRUE)
dst_obj.domain = RADEON_GEM_DOMAIN_GTT;
else
dst_obj.domain = RADEON_GEM_DOMAIN_VRAM;
if (!R600SetAccelState(pScrn,
&src_obj,
NULL,
&dst_obj,
accel_state->copy_vs_offset, accel_state->copy_ps_offset,
rop, planemask))
return FALSE;
if (accel_state->same_surface == TRUE) {
unsigned height = RADEON_ALIGN(pDst->drawable.height,
drmmode_get_height_align(pScrn, accel_state->dst_obj.tiling_flags));
unsigned long size = height * accel_state->dst_obj.pitch * pDst->drawable.bitsPerPixel/8;
if (accel_state->dst_obj.surface)
size = accel_state->dst_obj.surface->bo_size;
if (accel_state->copy_area_bo) {
radeon_bo_unref(accel_state->copy_area_bo);
accel_state->copy_area_bo = NULL;
}
accel_state->copy_area_bo = radeon_bo_open(info->bufmgr, 0, size, 0,
RADEON_GEM_DOMAIN_VRAM,
0);
if (!accel_state->copy_area_bo)
RADEON_FALLBACK(("temp copy surface alloc failed\n"));
radeon_cs_space_add_persistent_bo(info->cs, accel_state->copy_area_bo,
0, RADEON_GEM_DOMAIN_VRAM);
if (radeon_cs_space_check(info->cs)) {
radeon_bo_unref(accel_state->copy_area_bo);
accel_state->copy_area_bo = NULL;
return FALSE;
}
accel_state->copy_area = (void*)accel_state->copy_area_bo;
} else
EVERGREENDoPrepareCopy(pScrn);
if (accel_state->vsync)
RADEONVlineHelperClear(pScrn);
accel_state->dst_pix = pDst;
accel_state->src_pix = pSrc;
accel_state->xdir = xdir;
accel_state->ydir = ydir;
return TRUE;
}
static void
EVERGREENDoneCopy(PixmapPtr pDst)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
if (!accel_state->same_surface)
EVERGREENDoCopyVline(pDst);
if (accel_state->copy_area)
accel_state->copy_area = NULL;
}
static void
EVERGREENCopy(PixmapPtr pDst,
int srcX, int srcY,
int dstX, int dstY,
int w, int h)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
if (accel_state->same_surface && (srcX == dstX) && (srcY == dstY))
return;
if (CS_FULL(info->cs)) {
EVERGREENDoneCopy(info->accel_state->dst_pix);
radeon_cs_flush_indirect(pScrn);
EVERGREENPrepareCopy(accel_state->src_pix,
accel_state->dst_pix,
accel_state->xdir,
accel_state->ydir,
accel_state->rop,
accel_state->planemask);
}
if (accel_state->vsync)
RADEONVlineHelperSet(pScrn, dstX, dstY, dstX + w, dstY + h);
if (accel_state->same_surface &&
(srcX + w <= dstX || dstX + w <= srcX || srcY + h <= dstY || dstY + h <= srcY)) {
EVERGREENDoPrepareCopy(pScrn);
EVERGREENAppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, w, h);
EVERGREENDoCopyVline(pDst);
} else if (accel_state->same_surface && accel_state->copy_area) {
uint32_t orig_dst_domain = accel_state->dst_obj.domain;
uint32_t orig_src_domain = accel_state->src_obj[0].domain;
uint32_t orig_src_tiling_flags = accel_state->src_obj[0].tiling_flags;
uint32_t orig_dst_tiling_flags = accel_state->dst_obj.tiling_flags;
struct radeon_bo *orig_bo = accel_state->dst_obj.bo;
int orig_rop = accel_state->rop;
struct radeon_surface *orig_dst_surface = accel_state->dst_obj.surface;
struct radeon_surface *orig_src_surface = accel_state->src_obj[0].surface;
/* src to tmp */
accel_state->dst_obj.domain = RADEON_GEM_DOMAIN_VRAM;
accel_state->dst_obj.bo = accel_state->copy_area_bo;
accel_state->dst_obj.tiling_flags = 0;
accel_state->rop = 3;
accel_state->dst_obj.surface = NULL;
EVERGREENDoPrepareCopy(pScrn);
EVERGREENAppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, w, h);
EVERGREENDoCopy(pScrn);
/* tmp to dst */
accel_state->src_obj[0].domain = RADEON_GEM_DOMAIN_VRAM;
accel_state->src_obj[0].bo = accel_state->copy_area_bo;
accel_state->src_obj[0].tiling_flags = 0;
accel_state->src_obj[0].surface = NULL;
accel_state->dst_obj.domain = orig_dst_domain;
accel_state->dst_obj.bo = orig_bo;
accel_state->dst_obj.tiling_flags = orig_dst_tiling_flags;
accel_state->rop = orig_rop;
accel_state->dst_obj.surface = orig_dst_surface;
EVERGREENDoPrepareCopy(pScrn);
EVERGREENAppendCopyVertex(pScrn, dstX, dstY, dstX, dstY, w, h);
EVERGREENDoCopyVline(pDst);
/* restore state */
accel_state->src_obj[0].domain = orig_src_domain;
accel_state->src_obj[0].bo = orig_bo;
accel_state->src_obj[0].tiling_flags = orig_src_tiling_flags;
accel_state->src_obj[0].surface = orig_src_surface;
} else
EVERGREENAppendCopyVertex(pScrn, srcX, srcY, dstX, dstY, w, h);
}
struct blendinfo {
Bool dst_alpha;
Bool src_alpha;
uint32_t blend_cntl;
};
static struct blendinfo EVERGREENBlendOp[] = {
/* Clear */
{0, 0, (BLEND_ZERO << COLOR_SRCBLEND_shift) | (BLEND_ZERO << COLOR_DESTBLEND_shift)},
/* Src */
{0, 0, (BLEND_ONE << COLOR_SRCBLEND_shift) | (BLEND_ZERO << COLOR_DESTBLEND_shift)},
/* Dst */
{0, 0, (BLEND_ZERO << COLOR_SRCBLEND_shift) | (BLEND_ONE << COLOR_DESTBLEND_shift)},
/* Over */
{0, 1, (BLEND_ONE << COLOR_SRCBLEND_shift) | (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* OverReverse */
{1, 0, (BLEND_ONE_MINUS_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_ONE << COLOR_DESTBLEND_shift)},
/* In */
{1, 0, (BLEND_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_ZERO << COLOR_DESTBLEND_shift)},
/* InReverse */
{0, 1, (BLEND_ZERO << COLOR_SRCBLEND_shift) | (BLEND_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* Out */
{1, 0, (BLEND_ONE_MINUS_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_ZERO << COLOR_DESTBLEND_shift)},
/* OutReverse */
{0, 1, (BLEND_ZERO << COLOR_SRCBLEND_shift) | (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* Atop */
{1, 1, (BLEND_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* AtopReverse */
{1, 1, (BLEND_ONE_MINUS_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* Xor */
{1, 1, (BLEND_ONE_MINUS_DST_ALPHA << COLOR_SRCBLEND_shift) | (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)},
/* Add */
{0, 0, (BLEND_ONE << COLOR_SRCBLEND_shift) | (BLEND_ONE << COLOR_DESTBLEND_shift)},
};
struct formatinfo {
unsigned int fmt;
uint32_t card_fmt;
};
static struct formatinfo EVERGREENTexFormats[] = {
{PIXMAN_a2r10g10b10, FMT_2_10_10_10},
{PIXMAN_x2r10g10b10, FMT_2_10_10_10},
{PIXMAN_a2b10g10r10, FMT_2_10_10_10},
{PIXMAN_x2b10g10r10, FMT_2_10_10_10},
{PIXMAN_a8r8g8b8, FMT_8_8_8_8},
{PIXMAN_x8r8g8b8, FMT_8_8_8_8},
{PIXMAN_a8b8g8r8, FMT_8_8_8_8},
{PIXMAN_x8b8g8r8, FMT_8_8_8_8},
{PIXMAN_b8g8r8a8, FMT_8_8_8_8},
{PICT_b8g8r8x8, FMT_8_8_8_8},
{PICT_r5g6b5, FMT_5_6_5},
{PICT_a1r5g5b5, FMT_1_5_5_5},
{PICT_x1r5g5b5, FMT_1_5_5_5},
{PICT_a8, FMT_8},
};
static uint32_t EVERGREENGetBlendCntl(int op, PicturePtr pMask, uint32_t dst_format)
{
uint32_t sblend, dblend;
sblend = EVERGREENBlendOp[op].blend_cntl & COLOR_SRCBLEND_mask;
dblend = EVERGREENBlendOp[op].blend_cntl & COLOR_DESTBLEND_mask;
/* If there's no dst alpha channel, adjust the blend op so that we'll treat
* it as always 1.
*/
if (PICT_FORMAT_A(dst_format) == 0 && EVERGREENBlendOp[op].dst_alpha) {
if (sblend == (BLEND_DST_ALPHA << COLOR_SRCBLEND_shift))
sblend = (BLEND_ONE << COLOR_SRCBLEND_shift);
else if (sblend == (BLEND_ONE_MINUS_DST_ALPHA << COLOR_SRCBLEND_shift))
sblend = (BLEND_ZERO << COLOR_SRCBLEND_shift);
}
/* If the source alpha is being used, then we should only be in a case where
* the source blend factor is 0, and the source blend value is the mask
* channels multiplied by the source picture's alpha.
*/
if (pMask && pMask->componentAlpha && EVERGREENBlendOp[op].src_alpha) {
if (dblend == (BLEND_SRC_ALPHA << COLOR_DESTBLEND_shift)) {
dblend = (BLEND_SRC_COLOR << COLOR_DESTBLEND_shift);
} else if (dblend == (BLEND_ONE_MINUS_SRC_ALPHA << COLOR_DESTBLEND_shift)) {
dblend = (BLEND_ONE_MINUS_SRC_COLOR << COLOR_DESTBLEND_shift);
}
/* With some tricks, we can still accelerate PictOpOver with solid src.
* This is commonly used for text rendering, so it's worth the extra
* effort.
*/
if (sblend == (BLEND_ONE << COLOR_SRCBLEND_shift)) {
sblend = (BLEND_CONSTANT_COLOR << COLOR_SRCBLEND_shift);
}
}
return sblend | dblend;
}
static Bool EVERGREENGetDestFormat(PicturePtr pDstPicture, uint32_t *dst_format)
{
switch (pDstPicture->format) {
case PIXMAN_a2r10g10b10:
case PIXMAN_x2r10g10b10:
case PIXMAN_a2b10g10r10:
case PIXMAN_x2b10g10r10:
*dst_format = COLOR_2_10_10_10;
break;
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
case PIXMAN_a8b8g8r8:
case PIXMAN_x8b8g8r8:
case PIXMAN_b8g8r8a8:
case PICT_b8g8r8x8:
*dst_format = COLOR_8_8_8_8;
break;
case PICT_r5g6b5:
*dst_format = COLOR_5_6_5;
break;
case PICT_a1r5g5b5:
case PICT_x1r5g5b5:
*dst_format = COLOR_1_5_5_5;
break;
case PICT_a8:
*dst_format = COLOR_8;
break;
default:
RADEON_FALLBACK(("Unsupported dest format 0x%x\n",
(int)pDstPicture->format));
}
return TRUE;
}
static Bool EVERGREENCheckCompositeTexture(PicturePtr pPict,
PicturePtr pDstPict,
int op,
int unit)
{
unsigned int repeatType = pPict->repeat ? pPict->repeatType : RepeatNone;
unsigned int i;
for (i = 0; i < sizeof(EVERGREENTexFormats) / sizeof(EVERGREENTexFormats[0]); i++) {
if (EVERGREENTexFormats[i].fmt == pPict->format)
break;
}
if (i == sizeof(EVERGREENTexFormats) / sizeof(EVERGREENTexFormats[0]))
RADEON_FALLBACK(("Unsupported picture format 0x%x\n",
(int)pPict->format));
if (pPict->filter != PictFilterNearest &&
pPict->filter != PictFilterBilinear)
RADEON_FALLBACK(("Unsupported filter 0x%x\n", pPict->filter));
/* for REPEAT_NONE, Render semantics are that sampling outside the source
* picture results in alpha=0 pixels. We can implement this with a border color
* *if* our source texture has an alpha channel, otherwise we need to fall
* back. If we're not transformed then we hope that upper layers have clipped
* rendering to the bounds of the source drawable, in which case it doesn't
* matter. I have not, however, verified that the X server always does such
* clipping.
*/
/* FIXME evergreen */
if (pPict->transform != 0 && repeatType == RepeatNone && PICT_FORMAT_A(pPict->format) == 0) {
if (!(((op == PictOpSrc) || (op == PictOpClear)) && (PICT_FORMAT_A(pDstPict->format) == 0)))
RADEON_FALLBACK(("REPEAT_NONE unsupported for transformed xRGB source\n"));
}
if (!radeon_transform_is_affine_or_scaled(pPict->transform))
RADEON_FALLBACK(("non-affine transforms not supported\n"));
return TRUE;
}
static void EVERGREENXFormSetup(PicturePtr pPict, ScrnInfoPtr pScrn,
int unit, float *vs_alu_consts)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
int const_offset = unit * 8;
int w, h;
if (pPict->pDrawable) {
w = pPict->pDrawable->width;
h = pPict->pDrawable->height;
} else {
w = 1;
h = 1;
}
if (pPict->transform != 0) {
accel_state->is_transform[unit] = TRUE;
accel_state->transform[unit] = pPict->transform;
vs_alu_consts[0 + const_offset] = xFixedToFloat(pPict->transform->matrix[0][0]);
vs_alu_consts[1 + const_offset] = xFixedToFloat(pPict->transform->matrix[0][1]);
vs_alu_consts[2 + const_offset] = xFixedToFloat(pPict->transform->matrix[0][2]);
vs_alu_consts[3 + const_offset] = 1.0 / w;
vs_alu_consts[4 + const_offset] = xFixedToFloat(pPict->transform->matrix[1][0]);
vs_alu_consts[5 + const_offset] = xFixedToFloat(pPict->transform->matrix[1][1]);
vs_alu_consts[6 + const_offset] = xFixedToFloat(pPict->transform->matrix[1][2]);
vs_alu_consts[7 + const_offset] = 1.0 / h;
} else {
accel_state->is_transform[unit] = FALSE;
vs_alu_consts[0 + const_offset] = 1.0;
vs_alu_consts[1 + const_offset] = 0.0;
vs_alu_consts[2 + const_offset] = 0.0;
vs_alu_consts[3 + const_offset] = 1.0 / w;
vs_alu_consts[4 + const_offset] = 0.0;
vs_alu_consts[5 + const_offset] = 1.0;
vs_alu_consts[6 + const_offset] = 0.0;
vs_alu_consts[7 + const_offset] = 1.0 / h;
}
}
static Bool EVERGREENTextureSetup(PicturePtr pPict, PixmapPtr pPix,
int unit)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pPix->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
unsigned int repeatType;
unsigned int i;
tex_resource_t tex_res;
tex_sampler_t tex_samp;
int pix_r, pix_g, pix_b, pix_a;
CLEAR (tex_res);
CLEAR (tex_samp);
for (i = 0; i < sizeof(EVERGREENTexFormats) / sizeof(EVERGREENTexFormats[0]); i++) {
if (EVERGREENTexFormats[i].fmt == pPict->format)
break;
}
/* Texture */
if (pPict->pDrawable) {
tex_res.w = pPict->pDrawable->width;
tex_res.h = pPict->pDrawable->height;
repeatType = pPict->repeat ? pPict->repeatType : RepeatNone;
} else {
tex_res.w = 1;
tex_res.h = 1;
repeatType = RepeatNormal;
}
tex_res.id = unit;
tex_res.pitch = accel_state->src_obj[unit].pitch;
tex_res.depth = 0;
tex_res.dim = SQ_TEX_DIM_2D;
tex_res.base = 0;
tex_res.mip_base = 0;
tex_res.size = accel_state->src_size[unit];
tex_res.format = EVERGREENTexFormats[i].card_fmt;
tex_res.bo = accel_state->src_obj[unit].bo;
tex_res.mip_bo = accel_state->src_obj[unit].bo;
tex_res.surface = accel_state->src_obj[unit].surface;
#if X_BYTE_ORDER == X_BIG_ENDIAN
switch (accel_state->src_obj[unit].bpp) {
case 16:
tex_res.endian = SQ_ENDIAN_8IN16;
break;
case 32:
tex_res.endian = SQ_ENDIAN_8IN32;
break;
default :
break;
}
#endif
/* component swizzles */
switch (pPict->format) {
case PIXMAN_a2r10g10b10:
case PICT_a1r5g5b5:
case PIXMAN_a8r8g8b8:
pix_r = SQ_SEL_Z; /* R */
pix_g = SQ_SEL_Y; /* G */
pix_b = SQ_SEL_X; /* B */
pix_a = SQ_SEL_W; /* A */
break;
case PIXMAN_a2b10g10r10:
case PIXMAN_a8b8g8r8:
pix_r = SQ_SEL_X; /* R */
pix_g = SQ_SEL_Y; /* G */
pix_b = SQ_SEL_Z; /* B */
pix_a = SQ_SEL_W; /* A */
break;
case PIXMAN_x2b10g10r10:
case PIXMAN_x8b8g8r8:
pix_r = SQ_SEL_X; /* R */
pix_g = SQ_SEL_Y; /* G */
pix_b = SQ_SEL_Z; /* B */
pix_a = SQ_SEL_1; /* A */
break;
case PIXMAN_b8g8r8a8:
pix_r = SQ_SEL_Y; /* R */
pix_g = SQ_SEL_Z; /* G */
pix_b = SQ_SEL_W; /* B */
pix_a = SQ_SEL_X; /* A */
break;
case PICT_b8g8r8x8:
pix_r = SQ_SEL_Y; /* R */
pix_g = SQ_SEL_Z; /* G */
pix_b = SQ_SEL_W; /* B */
pix_a = SQ_SEL_1; /* A */
break;
case PIXMAN_x2r10g10b10:
case PICT_x1r5g5b5:
case PIXMAN_x8r8g8b8:
case PICT_r5g6b5:
pix_r = SQ_SEL_Z; /* R */
pix_g = SQ_SEL_Y; /* G */
pix_b = SQ_SEL_X; /* B */
pix_a = SQ_SEL_1; /* A */
break;
case PICT_a8:
pix_r = SQ_SEL_0; /* R */
pix_g = SQ_SEL_0; /* G */
pix_b = SQ_SEL_0; /* B */
pix_a = SQ_SEL_X; /* A */
break;
default:
RADEON_FALLBACK(("Bad format 0x%x\n", pPict->format));
}
if (unit == 0) {
if (!accel_state->msk_pic) {
if (PICT_FORMAT_RGB(pPict->format) == 0) {
pix_r = SQ_SEL_0;
pix_g = SQ_SEL_0;
pix_b = SQ_SEL_0;
}
if (PICT_FORMAT_A(pPict->format) == 0)
pix_a = SQ_SEL_1;
} else {
if (accel_state->component_alpha) {
if (accel_state->src_alpha) {
if (PICT_FORMAT_A(pPict->format) == 0) {
pix_r = SQ_SEL_1;
pix_g = SQ_SEL_1;
pix_b = SQ_SEL_1;
pix_a = SQ_SEL_1;
} else {
pix_r = pix_a;
pix_g = pix_a;
pix_b = pix_a;
}
} else {
if (PICT_FORMAT_A(pPict->format) == 0)
pix_a = SQ_SEL_1;
}
} else {
if (PICT_FORMAT_RGB(pPict->format) == 0) {
pix_r = SQ_SEL_0;
pix_g = SQ_SEL_0;
pix_b = SQ_SEL_0;
}
if (PICT_FORMAT_A(pPict->format) == 0)
pix_a = SQ_SEL_1;
}
}
} else {
if (accel_state->component_alpha) {
if (PICT_FORMAT_A(pPict->format) == 0)
pix_a = SQ_SEL_1;
} else {
if (PICT_FORMAT_A(pPict->format) == 0) {
pix_r = SQ_SEL_1;
pix_g = SQ_SEL_1;
pix_b = SQ_SEL_1;
pix_a = SQ_SEL_1;
} else {
pix_r = pix_a;
pix_g = pix_a;
pix_b = pix_a;
}
}
}
tex_res.dst_sel_x = pix_r; /* R */
tex_res.dst_sel_y = pix_g; /* G */
tex_res.dst_sel_z = pix_b; /* B */
tex_res.dst_sel_w = pix_a; /* A */
tex_res.base_level = 0;
tex_res.last_level = 0;
tex_res.perf_modulation = 0;
if ((accel_state->src_obj[unit].tiling_flags & RADEON_TILING_MASK) ==
RADEON_TILING_LINEAR)
tex_res.array_mode = 0;
evergreen_set_tex_resource (pScrn, &tex_res, accel_state->src_obj[unit].domain);
tex_samp.id = unit;
tex_samp.border_color = SQ_TEX_BORDER_COLOR_TRANS_BLACK;
switch (repeatType) {
case RepeatNormal:
tex_samp.clamp_x = SQ_TEX_WRAP;
tex_samp.clamp_y = SQ_TEX_WRAP;
break;
case RepeatPad:
tex_samp.clamp_x = SQ_TEX_CLAMP_LAST_TEXEL;
tex_samp.clamp_y = SQ_TEX_CLAMP_LAST_TEXEL;
break;
case RepeatReflect:
tex_samp.clamp_x = SQ_TEX_MIRROR;
tex_samp.clamp_y = SQ_TEX_MIRROR;
break;
case RepeatNone:
tex_samp.clamp_x = SQ_TEX_CLAMP_BORDER;
tex_samp.clamp_y = SQ_TEX_CLAMP_BORDER;
break;
default:
RADEON_FALLBACK(("Bad repeat 0x%x\n", repeatType));
}
switch (pPict->filter) {
case PictFilterNearest:
tex_samp.xy_mag_filter = SQ_TEX_XY_FILTER_POINT;
tex_samp.xy_min_filter = SQ_TEX_XY_FILTER_POINT;
tex_samp.mc_coord_truncate = 1;
break;
case PictFilterBilinear:
tex_samp.xy_mag_filter = SQ_TEX_XY_FILTER_BILINEAR;
tex_samp.xy_min_filter = SQ_TEX_XY_FILTER_BILINEAR;
break;
default:
RADEON_FALLBACK(("Bad filter 0x%x\n", pPict->filter));
}
tex_samp.clamp_z = SQ_TEX_WRAP;
tex_samp.z_filter = SQ_TEX_Z_FILTER_NONE;
tex_samp.mip_filter = 0; /* no mipmap */
evergreen_set_tex_sampler (pScrn, &tex_samp);
return TRUE;
}
static Bool EVERGREENCheckComposite(int op, PicturePtr pSrcPicture,
PicturePtr pMaskPicture,
PicturePtr pDstPicture)
{
uint32_t tmp1;
PixmapPtr pSrcPixmap, pDstPixmap;
/* Check for unsupported compositing operations. */
if (op >= (int) (sizeof(EVERGREENBlendOp) / sizeof(EVERGREENBlendOp[0])))
RADEON_FALLBACK(("Unsupported Composite op 0x%x\n", op));
if (pSrcPicture->pDrawable) {
pSrcPixmap = RADEONGetDrawablePixmap(pSrcPicture->pDrawable);
if (pSrcPixmap->drawable.width >= 16384 ||
pSrcPixmap->drawable.height >= 16384) {
RADEON_FALLBACK(("Source w/h too large (%d,%d).\n",
pSrcPixmap->drawable.width,
pSrcPixmap->drawable.height));
}
if (!EVERGREENCheckCompositeTexture(pSrcPicture, pDstPicture, op, 0))
return FALSE;
} else if (pSrcPicture->pSourcePict->type != SourcePictTypeSolidFill)
RADEON_FALLBACK(("Gradient pictures not supported yet\n"));
pDstPixmap = RADEONGetDrawablePixmap(pDstPicture->pDrawable);
if (pDstPixmap->drawable.width >= 16384 ||
pDstPixmap->drawable.height >= 16384) {
RADEON_FALLBACK(("Dest w/h too large (%d,%d).\n",
pDstPixmap->drawable.width,
pDstPixmap->drawable.height));
}
if (pMaskPicture) {
PixmapPtr pMaskPixmap;
if (pMaskPicture->pDrawable) {
pMaskPixmap = RADEONGetDrawablePixmap(pMaskPicture->pDrawable);
if (pMaskPixmap->drawable.width >= 16384 ||
pMaskPixmap->drawable.height >= 16384) {
RADEON_FALLBACK(("Mask w/h too large (%d,%d).\n",
pMaskPixmap->drawable.width,
pMaskPixmap->drawable.height));
}
if (pMaskPicture->componentAlpha) {
/* Check if it's component alpha that relies on a source alpha and
* on the source value. We can only get one of those into the
* single source value that we get to blend with.
*
* We can cheat a bit if the src is solid, though. PictOpOver
* can use the constant blend color to sneak a second blend
* source in.
*/
if (EVERGREENBlendOp[op].src_alpha &&
(EVERGREENBlendOp[op].blend_cntl & COLOR_SRCBLEND_mask) !=
(BLEND_ZERO << COLOR_SRCBLEND_shift)) {
if (pSrcPicture->pDrawable || op != PictOpOver)
RADEON_FALLBACK(("Component alpha not supported with source "
"alpha and source value blending.\n"));
}
}
if (!EVERGREENCheckCompositeTexture(pMaskPicture, pDstPicture, op, 1))
return FALSE;
} else if (pMaskPicture->pSourcePict->type != SourcePictTypeSolidFill)
RADEON_FALLBACK(("Gradient pictures not supported yet\n"));
}
if (!EVERGREENGetDestFormat(pDstPicture, &tmp1))
return FALSE;
return TRUE;
}
static void EVERGREENSetSolidConsts(ScrnInfoPtr pScrn, float *buf, int format, uint32_t fg, int unit)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
float pix_r = 0, pix_g = 0, pix_b = 0, pix_a = 0;
uint32_t w = (fg >> 24) & 0xff;
uint32_t z = (fg >> 16) & 0xff;
uint32_t y = (fg >> 8) & 0xff;
uint32_t x = (fg >> 0) & 0xff;
float xf = (float)x / 255; /* R */
float yf = (float)y / 255; /* G */
float zf = (float)z / 255; /* B */
float wf = (float)w / 255; /* A */
/* component swizzles */
switch (format) {
case PICT_a1r5g5b5:
case PIXMAN_a8r8g8b8:
pix_r = zf; /* R */
pix_g = yf; /* G */
pix_b = xf; /* B */
pix_a = wf; /* A */
break;
case PIXMAN_a8b8g8r8:
pix_r = xf; /* R */
pix_g = yf; /* G */
pix_b = zf; /* B */
pix_a = wf; /* A */
break;
case PIXMAN_x8b8g8r8:
pix_r = xf; /* R */
pix_g = yf; /* G */
pix_b = zf; /* B */
pix_a = 1.0; /* A */
break;
case PIXMAN_b8g8r8a8:
pix_r = yf; /* R */
pix_g = zf; /* G */
pix_b = wf; /* B */
pix_a = xf; /* A */
break;
case PICT_b8g8r8x8:
pix_r = yf; /* R */
pix_g = zf; /* G */
pix_b = wf; /* B */
pix_a = 1.0; /* A */
break;
case PICT_x1r5g5b5:
case PIXMAN_x8r8g8b8:
case PICT_r5g6b5:
pix_r = zf; /* R */
pix_g = yf; /* G */
pix_b = xf; /* B */
pix_a = 1.0; /* A */
break;
case PICT_a8:
pix_r = 0.0; /* R */
pix_g = 0.0; /* G */
pix_b = 0.0; /* B */
pix_a = xf; /* A */
break;
default:
ErrorF("Bad format 0x%x\n", format);
}
if (unit == 0) {
if (!accel_state->msk_pic) {
if (PICT_FORMAT_RGB(format) == 0) {
pix_r = 0.0;
pix_g = 0.0;
pix_b = 0.0;
}
if (PICT_FORMAT_A(format) == 0)
pix_a = 1.0;
} else {
if (accel_state->component_alpha) {
if (accel_state->src_alpha) {
/* required for PictOpOver */
float cblend[4] = { pix_r / pix_a, pix_g / pix_a,
pix_b / pix_a, pix_a / pix_a };
evergreen_set_blend_color(pScrn, cblend);
if (PICT_FORMAT_A(format) == 0) {
pix_r = 1.0;
pix_g = 1.0;
pix_b = 1.0;
pix_a = 1.0;
} else {
pix_r = pix_a;
pix_g = pix_a;
pix_b = pix_a;
}
} else {
if (PICT_FORMAT_A(format) == 0)
pix_a = 1.0;
}
} else {
if (PICT_FORMAT_RGB(format) == 0) {
pix_r = 0;
pix_g = 0;
pix_b = 0;
}
if (PICT_FORMAT_A(format) == 0)
pix_a = 1.0;
}
}
} else {
if (accel_state->component_alpha) {
if (PICT_FORMAT_A(format) == 0)
pix_a = 1.0;
} else {
if (PICT_FORMAT_A(format) == 0) {
pix_r = 1.0;
pix_g = 1.0;
pix_b = 1.0;
pix_a = 1.0;
} else {
pix_r = pix_a;
pix_g = pix_a;
pix_b = pix_a;
}
}
}
buf[0] = pix_r;
buf[1] = pix_g;
buf[2] = pix_b;
buf[3] = pix_a;
}
static Bool EVERGREENPrepareComposite(int op, PicturePtr pSrcPicture,
PicturePtr pMaskPicture, PicturePtr pDstPicture,
PixmapPtr pSrc, PixmapPtr pMask, PixmapPtr pDst)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
uint32_t dst_format;
cb_config_t cb_conf;
shader_config_t vs_conf, ps_conf;
const_config_t vs_const_conf;
struct r600_accel_object src_obj, mask_obj, dst_obj;
float *cbuf;
uint32_t ps_bool_consts = 0;
if (pDst->drawable.bitsPerPixel < 8 || (pSrc && pSrc->drawable.bitsPerPixel < 8))
return FALSE;
if (pSrc) {
src_obj.bo = radeon_get_pixmap_bo(pSrc)->bo.radeon;
src_obj.surface = radeon_get_pixmap_surface(pSrc);
src_obj.tiling_flags = radeon_get_pixmap_tiling(pSrc);
src_obj.pitch = exaGetPixmapPitch(pSrc) / (pSrc->drawable.bitsPerPixel / 8);
src_obj.width = pSrc->drawable.width;
src_obj.height = pSrc->drawable.height;
src_obj.bpp = pSrc->drawable.bitsPerPixel;
src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT;
}
dst_obj.bo = radeon_get_pixmap_bo(pDst)->bo.radeon;
dst_obj.surface = radeon_get_pixmap_surface(pDst);
dst_obj.tiling_flags = radeon_get_pixmap_tiling(pDst);
dst_obj.pitch = exaGetPixmapPitch(pDst) / (pDst->drawable.bitsPerPixel / 8);
dst_obj.width = pDst->drawable.width;
dst_obj.height = pDst->drawable.height;
dst_obj.bpp = pDst->drawable.bitsPerPixel;
if (radeon_get_pixmap_shared(pDst) == TRUE)
dst_obj.domain = RADEON_GEM_DOMAIN_GTT;
else
dst_obj.domain = RADEON_GEM_DOMAIN_VRAM;
if (pMaskPicture) {
if (pMask) {
mask_obj.bo = radeon_get_pixmap_bo(pMask)->bo.radeon;
mask_obj.tiling_flags = radeon_get_pixmap_tiling(pMask);
mask_obj.pitch = exaGetPixmapPitch(pMask) / (pMask->drawable.bitsPerPixel / 8);
mask_obj.surface = radeon_get_pixmap_surface(pMask);
mask_obj.width = pMask->drawable.width;
mask_obj.height = pMask->drawable.height;
mask_obj.bpp = pMask->drawable.bitsPerPixel;
mask_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT;
}
accel_state->msk_pic = pMaskPicture;
if (pMaskPicture->componentAlpha) {
accel_state->component_alpha = TRUE;
if (EVERGREENBlendOp[op].src_alpha)
accel_state->src_alpha = TRUE;
else
accel_state->src_alpha = FALSE;
} else {
accel_state->component_alpha = FALSE;
accel_state->src_alpha = FALSE;
}
} else {
accel_state->msk_pic = NULL;
accel_state->component_alpha = FALSE;
accel_state->src_alpha = FALSE;
}
if (!R600SetAccelState(pScrn,
pSrc ? &src_obj : NULL,
(pMaskPicture && pMask) ? &mask_obj : NULL,
&dst_obj,
accel_state->comp_vs_offset, accel_state->comp_ps_offset,
3, 0xffffffff))
return FALSE;
if (!EVERGREENGetDestFormat(pDstPicture, &dst_format))
return FALSE;
CLEAR (cb_conf);
CLEAR (vs_conf);
CLEAR (ps_conf);
CLEAR (vs_const_conf);
if (pMask)
radeon_vbo_check(pScrn, &accel_state->vbo, 24);
else
radeon_vbo_check(pScrn, &accel_state->vbo, 16);
radeon_vbo_check(pScrn, &accel_state->cbuf, 256);
radeon_cp_start(pScrn);
evergreen_set_default_state(pScrn);
evergreen_set_generic_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_screen_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
evergreen_set_window_scissor(pScrn, 0, 0, accel_state->dst_obj.width, accel_state->dst_obj.height);
if (pSrc) {
if (!EVERGREENTextureSetup(pSrcPicture, pSrc, 0)) {
radeon_ib_discard(pScrn);
radeon_cs_flush_indirect(pScrn);
return FALSE;
}
} else
accel_state->is_transform[0] = FALSE;
if (pMask) {
if (!EVERGREENTextureSetup(pMaskPicture, pMask, 1)) {
radeon_ib_discard(pScrn);
radeon_cs_flush_indirect(pScrn);
return FALSE;
}
} else
accel_state->is_transform[1] = FALSE;
if (pSrc)
ps_bool_consts |= (1 << 0);
if (pMask)
ps_bool_consts |= (1 << 1);
evergreen_set_bool_consts(pScrn, SQ_BOOL_CONST_ps, ps_bool_consts);
if (pMask) {
evergreen_set_bool_consts(pScrn, SQ_BOOL_CONST_vs, (1 << 0));
} else {
evergreen_set_bool_consts(pScrn, SQ_BOOL_CONST_vs, (0 << 0));
}
/* Shader */
vs_conf.shader_addr = accel_state->vs_mc_addr;
vs_conf.shader_size = accel_state->vs_size;
vs_conf.num_gprs = 5;
vs_conf.stack_size = 1;
vs_conf.bo = accel_state->shaders_bo;
evergreen_vs_setup(pScrn, &vs_conf, RADEON_GEM_DOMAIN_VRAM);
ps_conf.shader_addr = accel_state->ps_mc_addr;
ps_conf.shader_size = accel_state->ps_size;
ps_conf.num_gprs = 2;
ps_conf.stack_size = 1;
ps_conf.clamp_consts = 0;
ps_conf.export_mode = 2;
ps_conf.bo = accel_state->shaders_bo;
evergreen_ps_setup(pScrn, &ps_conf, RADEON_GEM_DOMAIN_VRAM);
cb_conf.id = 0;
cb_conf.w = accel_state->dst_obj.pitch;
cb_conf.h = accel_state->dst_obj.height;
cb_conf.base = 0;
cb_conf.format = dst_format;
cb_conf.bo = accel_state->dst_obj.bo;
cb_conf.surface = accel_state->dst_obj.surface;
switch (pDstPicture->format) {
case PIXMAN_a2r10g10b10:
case PIXMAN_x2r10g10b10:
case PIXMAN_a8r8g8b8:
case PIXMAN_x8r8g8b8:
case PICT_a1r5g5b5:
case PICT_x1r5g5b5:
default:
cb_conf.comp_swap = 1; /* ARGB */
break;
case PIXMAN_a2b10g10r10:
case PIXMAN_x2b10g10r10:
case PIXMAN_a8b8g8r8:
case PIXMAN_x8b8g8r8:
cb_conf.comp_swap = 0; /* ABGR */
break;
case PIXMAN_b8g8r8a8:
case PICT_b8g8r8x8:
cb_conf.comp_swap = 3; /* BGRA */
break;
case PICT_r5g6b5:
cb_conf.comp_swap = 2; /* RGB */
break;
case PICT_a8:
cb_conf.comp_swap = 3; /* A */
break;
}
cb_conf.source_format = EXPORT_4C_16BPC;
cb_conf.blend_clamp = 1;
cb_conf.blendcntl = EVERGREENGetBlendCntl(op, pMaskPicture, pDstPicture->format);
cb_conf.blendcntl |= CB_BLEND0_CONTROL__ENABLE_bit;
cb_conf.rop = 3;
cb_conf.pmask = 0xf;
if ((accel_state->dst_obj.tiling_flags & RADEON_TILING_MASK) ==
RADEON_TILING_LINEAR) {
cb_conf.array_mode = 0;
cb_conf.non_disp_tiling = 1;
}
#if X_BYTE_ORDER == X_BIG_ENDIAN
switch (dst_obj.bpp) {
case 16:
cb_conf.endian = ENDIAN_8IN16;
break;
case 32:
cb_conf.endian = ENDIAN_8IN32;
break;
default:
break;
}
#endif
evergreen_set_render_target(pScrn, &cb_conf, accel_state->dst_obj.domain);
if (pMask)
evergreen_set_spi(pScrn, (2 - 1), 2);
else
evergreen_set_spi(pScrn, (1 - 1), 1);
/* VS alu constants */
vs_const_conf.size_bytes = 256;
vs_const_conf.type = SHADER_TYPE_VS;
cbuf = radeon_vbo_space(pScrn, &accel_state->cbuf, 256);
vs_const_conf.bo = accel_state->cbuf.vb_bo;
vs_const_conf.const_addr = accel_state->cbuf.vb_offset;
vs_const_conf.cpu_ptr = (uint32_t *)(char *)cbuf;
EVERGREENXFormSetup(pSrcPicture, pScrn, 0, cbuf);
if (pMask)
EVERGREENXFormSetup(pMaskPicture, pScrn, 1, cbuf);
if (!pSrc) {
/* solid src color */
EVERGREENSetSolidConsts(pScrn, &cbuf[16], pSrcPicture->format,
pSrcPicture->pSourcePict->solidFill.color, 0);
}
if (!pMaskPicture) {
/* use identity constant if there is no mask */
cbuf[20] = 1.0;
cbuf[21] = 1.0;
cbuf[22] = 1.0;
cbuf[23] = 1.0;
} else if (!pMask) {
/* solid mask color */
EVERGREENSetSolidConsts(pScrn, &cbuf[20], pMaskPicture->format,
pMaskPicture->pSourcePict->solidFill.color, 1);
}
radeon_vbo_commit(pScrn, &accel_state->cbuf);
evergreen_set_alu_consts(pScrn, &vs_const_conf, RADEON_GEM_DOMAIN_GTT);
if (accel_state->vsync)
RADEONVlineHelperClear(pScrn);
accel_state->composite_op = op;
accel_state->dst_pic = pDstPicture;
accel_state->src_pic = pSrcPicture;
accel_state->dst_pix = pDst;
accel_state->msk_pix = pMask;
accel_state->src_pix = pSrc;
return TRUE;
}
static void EVERGREENFinishComposite(ScrnInfoPtr pScrn, PixmapPtr pDst,
struct radeon_accel_state *accel_state)
{
int vtx_size;
if (accel_state->vsync)
evergreen_cp_wait_vline_sync(pScrn, pDst,
accel_state->vline_crtc,
accel_state->vline_y1,
accel_state->vline_y2);
vtx_size = accel_state->msk_pix ? 24 : 16;
evergreen_finish_op(pScrn, vtx_size);
}
static void EVERGREENDoneComposite(PixmapPtr pDst)
{
ScreenPtr pScreen = pDst->drawable.pScreen;
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
EVERGREENFinishComposite(pScrn, pDst, accel_state);
}
static void EVERGREENComposite(PixmapPtr pDst,
int srcX, int srcY,
int maskX, int maskY,
int dstX, int dstY,
int w, int h)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
float *vb;
if (CS_FULL(info->cs)) {
EVERGREENFinishComposite(pScrn, pDst, info->accel_state);
radeon_cs_flush_indirect(pScrn);
EVERGREENPrepareComposite(info->accel_state->composite_op,
info->accel_state->src_pic,
info->accel_state->msk_pic,
info->accel_state->dst_pic,
info->accel_state->src_pix,
info->accel_state->msk_pix,
info->accel_state->dst_pix);
}
if (accel_state->vsync)
RADEONVlineHelperSet(pScrn, dstX, dstY, dstX + w, dstY + h);
if (accel_state->msk_pix) {
vb = radeon_vbo_space(pScrn, &accel_state->vbo, 24);
vb[0] = (float)dstX;
vb[1] = (float)dstY;
vb[2] = (float)srcX;
vb[3] = (float)srcY;
vb[4] = (float)maskX;
vb[5] = (float)maskY;
vb[6] = (float)dstX;
vb[7] = (float)(dstY + h);
vb[8] = (float)srcX;
vb[9] = (float)(srcY + h);
vb[10] = (float)maskX;
vb[11] = (float)(maskY + h);
vb[12] = (float)(dstX + w);
vb[13] = (float)(dstY + h);
vb[14] = (float)(srcX + w);
vb[15] = (float)(srcY + h);
vb[16] = (float)(maskX + w);
vb[17] = (float)(maskY + h);
radeon_vbo_commit(pScrn, &accel_state->vbo);
} else {
vb = radeon_vbo_space(pScrn, &accel_state->vbo, 16);
vb[0] = (float)dstX;
vb[1] = (float)dstY;
vb[2] = (float)srcX;
vb[3] = (float)srcY;
vb[4] = (float)dstX;
vb[5] = (float)(dstY + h);
vb[6] = (float)srcX;
vb[7] = (float)(srcY + h);
vb[8] = (float)(dstX + w);
vb[9] = (float)(dstY + h);
vb[10] = (float)(srcX + w);
vb[11] = (float)(srcY + h);
radeon_vbo_commit(pScrn, &accel_state->vbo);
}
}
static Bool
EVERGREENUploadToScreen(PixmapPtr pDst, int x, int y, int w, int h,
char *src, int src_pitch)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pDst->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
struct radeon_exa_pixmap_priv *driver_priv;
struct radeon_bo *scratch = NULL;
struct radeon_bo *copy_dst;
unsigned char *dst;
unsigned size;
uint32_t dst_domain;
int bpp = pDst->drawable.bitsPerPixel;
uint32_t scratch_pitch;
uint32_t copy_pitch;
uint32_t dst_pitch_hw = exaGetPixmapPitch(pDst) / (bpp / 8);
int ret;
Bool flush = TRUE;
Bool r;
int i;
struct r600_accel_object src_obj, dst_obj;
uint32_t height, base_align;
if (bpp < 8)
return FALSE;
driver_priv = exaGetPixmapDriverPrivate(pDst);
if (!driver_priv || !driver_priv->bo->bo.radeon)
return FALSE;
/* If we know the BO won't be busy / in VRAM, don't bother with a scratch */
copy_dst = driver_priv->bo->bo.radeon;
copy_pitch = pDst->devKind;
if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
if (!radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
flush = FALSE;
if (!radeon_bo_is_busy(driver_priv->bo->bo.radeon, &dst_domain) &&
!(dst_domain & RADEON_GEM_DOMAIN_VRAM))
goto copy;
}
}
scratch_pitch = RADEON_ALIGN(w, drmmode_get_pitch_align(pScrn, (bpp / 8), 0));
height = RADEON_ALIGN(h, drmmode_get_height_align(pScrn, 0));
base_align = drmmode_get_base_align(pScrn, (bpp / 8), 0);
size = scratch_pitch * height * (bpp / 8);
scratch = radeon_bo_open(info->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_GTT, 0);
if (!scratch) {
goto copy;
}
src_obj.pitch = scratch_pitch;
src_obj.width = w;
src_obj.height = h;
src_obj.bpp = bpp;
src_obj.domain = RADEON_GEM_DOMAIN_GTT;
src_obj.bo = scratch;
src_obj.tiling_flags = 0;
src_obj.surface = NULL;
dst_obj.pitch = dst_pitch_hw;
dst_obj.width = pDst->drawable.width;
dst_obj.height = pDst->drawable.height;
dst_obj.bpp = bpp;
dst_obj.domain = RADEON_GEM_DOMAIN_VRAM;
dst_obj.bo = radeon_get_pixmap_bo(pDst)->bo.radeon;
dst_obj.tiling_flags = radeon_get_pixmap_tiling(pDst);
dst_obj.surface = radeon_get_pixmap_surface(pDst);
if (!R600SetAccelState(pScrn,
&src_obj,
NULL,
&dst_obj,
accel_state->copy_vs_offset, accel_state->copy_ps_offset,
3, 0xffffffff)) {
goto copy;
}
copy_dst = scratch;
copy_pitch = scratch_pitch * (bpp / 8);
flush = FALSE;
copy:
if (flush)
radeon_cs_flush_indirect(pScrn);
ret = radeon_bo_map(copy_dst, 0);
if (ret) {
r = FALSE;
goto out;
}
r = TRUE;
size = w * bpp / 8;
dst = copy_dst->ptr;
if (copy_dst == driver_priv->bo->bo.radeon)
dst += y * copy_pitch + x * bpp / 8;
for (i = 0; i < h; i++) {
memcpy(dst + i * copy_pitch, src, size);
src += src_pitch;
}
radeon_bo_unmap(copy_dst);
if (copy_dst == scratch) {
if (info->accel_state->vsync)
RADEONVlineHelperSet(pScrn, x, y, x + w, y + h);
/* blit from gart to vram */
EVERGREENDoPrepareCopy(pScrn);
EVERGREENAppendCopyVertex(pScrn, 0, 0, x, y, w, h);
EVERGREENDoCopyVline(pDst);
}
out:
if (scratch)
radeon_bo_unref(scratch);
return r;
}
static Bool
EVERGREENDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w,
int h, char *dst, int dst_pitch)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pSrc->drawable.pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
struct radeon_exa_pixmap_priv *driver_priv;
struct radeon_bo *scratch = NULL;
struct radeon_bo *copy_src;
unsigned size;
uint32_t src_domain = 0;
int bpp = pSrc->drawable.bitsPerPixel;
uint32_t scratch_pitch;
uint32_t copy_pitch;
uint32_t src_pitch_hw = exaGetPixmapPitch(pSrc) / (bpp / 8);
int ret;
Bool flush = FALSE;
Bool r;
struct r600_accel_object src_obj, dst_obj;
uint32_t height, base_align;
if (bpp < 8)
return FALSE;
driver_priv = exaGetPixmapDriverPrivate(pSrc);
if (!driver_priv || !driver_priv->bo->bo.radeon)
return FALSE;
/* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
copy_src = driver_priv->bo->bo.radeon;
copy_pitch = pSrc->devKind;
if (!(driver_priv->tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
if (radeon_bo_is_referenced_by_cs(driver_priv->bo->bo.radeon, info->cs)) {
src_domain = radeon_bo_get_src_domain(driver_priv->bo->bo.radeon);
if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
(RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
src_domain = 0;
else /* A write may be scheduled */
flush = TRUE;
}
if (!src_domain)
radeon_bo_is_busy(driver_priv->bo->bo.radeon, &src_domain);
if (src_domain & ~(uint32_t)RADEON_GEM_DOMAIN_VRAM)
goto copy;
}
if (!accel_state->allowHWDFS)
goto copy;
scratch_pitch = RADEON_ALIGN(w, drmmode_get_pitch_align(pScrn, (bpp / 8), 0));
height = RADEON_ALIGN(h, drmmode_get_height_align(pScrn, 0));
base_align = drmmode_get_base_align(pScrn, (bpp / 8), 0);
size = scratch_pitch * height * (bpp / 8);
scratch = radeon_bo_open(info->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_GTT, 0);
if (!scratch) {
goto copy;
}
radeon_cs_space_reset_bos(info->cs);
radeon_cs_space_add_persistent_bo(info->cs, info->accel_state->shaders_bo,
RADEON_GEM_DOMAIN_VRAM, 0);
accel_state->src_obj[0].domain = RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM;
radeon_add_pixmap(info->cs, pSrc, info->accel_state->src_obj[0].domain, 0);
accel_state->dst_obj.domain = RADEON_GEM_DOMAIN_GTT;
radeon_cs_space_add_persistent_bo(info->cs, scratch, 0, accel_state->dst_obj.domain);
ret = radeon_cs_space_check(info->cs);
if (ret) {
goto copy;
}
src_obj.pitch = src_pitch_hw;
src_obj.width = pSrc->drawable.width;
src_obj.height = pSrc->drawable.height;
src_obj.bpp = bpp;
src_obj.domain = RADEON_GEM_DOMAIN_VRAM | RADEON_GEM_DOMAIN_GTT;
src_obj.bo = radeon_get_pixmap_bo(pSrc)->bo.radeon;
src_obj.tiling_flags = radeon_get_pixmap_tiling(pSrc);
src_obj.surface = radeon_get_pixmap_surface(pSrc);
dst_obj.pitch = scratch_pitch;
dst_obj.width = w;
dst_obj.height = h;
dst_obj.bo = scratch;
dst_obj.bpp = bpp;
dst_obj.domain = RADEON_GEM_DOMAIN_GTT;
dst_obj.tiling_flags = 0;
dst_obj.surface = NULL;
if (!R600SetAccelState(pScrn,
&src_obj,
NULL,
&dst_obj,
accel_state->copy_vs_offset, accel_state->copy_ps_offset,
3, 0xffffffff)) {
goto copy;
}
/* blit from vram to gart */
EVERGREENDoPrepareCopy(pScrn);
EVERGREENAppendCopyVertex(pScrn, x, y, 0, 0, w, h);
EVERGREENDoCopy(pScrn);
copy_src = scratch;
copy_pitch = scratch_pitch * (bpp / 8);
flush = TRUE;
copy:
if (flush)
radeon_cs_flush_indirect(pScrn);
ret = radeon_bo_map(copy_src, 0);
if (ret) {
ErrorF("failed to map pixmap: %d\n", ret);
r = FALSE;
goto out;
}
r = TRUE;
w *= bpp / 8;
if (copy_src == driver_priv->bo->bo.radeon)
size = y * copy_pitch + x * bpp / 8;
else
size = 0;
while (h--) {
memcpy(dst, copy_src->ptr + size, w);
size += copy_pitch;
dst += dst_pitch;
}
radeon_bo_unmap(copy_src);
out:
if (scratch)
radeon_bo_unref(scratch);
return r;
}
static int
EVERGREENMarkSync(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
return ++accel_state->exaSyncMarker;
}
static void
EVERGREENSync(ScreenPtr pScreen, int marker)
{
return;
}
static Bool
EVERGREENAllocShaders(ScrnInfoPtr pScrn, ScreenPtr pScreen)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
/* 512 bytes per shader for now */
int size = 512 * 9;
accel_state->shaders_bo = radeon_bo_open(info->bufmgr, 0, size, 0,
RADEON_GEM_DOMAIN_VRAM, 0);
if (!accel_state->shaders_bo) {
ErrorF("Allocating shader failed\n");
return FALSE;
}
return TRUE;
}
static Bool
EVERGREENLoadShaders(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
RADEONChipFamily ChipSet = info->ChipFamily;
uint32_t *shader;
int ret;
ret = radeon_bo_map(accel_state->shaders_bo, 1);
if (ret) {
FatalError("failed to map shader %d\n", ret);
return FALSE;
}
shader = accel_state->shaders_bo->ptr;
/* solid vs --------------------------------------- */
accel_state->solid_vs_offset = 0;
evergreen_solid_vs(ChipSet, shader + accel_state->solid_vs_offset / 4);
/* solid ps --------------------------------------- */
accel_state->solid_ps_offset = 512;
evergreen_solid_ps(ChipSet, shader + accel_state->solid_ps_offset / 4);
/* copy vs --------------------------------------- */
accel_state->copy_vs_offset = 1024;
evergreen_copy_vs(ChipSet, shader + accel_state->copy_vs_offset / 4);
/* copy ps --------------------------------------- */
accel_state->copy_ps_offset = 1536;
evergreen_copy_ps(ChipSet, shader + accel_state->copy_ps_offset / 4);
/* comp vs --------------------------------------- */
accel_state->comp_vs_offset = 2048;
evergreen_comp_vs(ChipSet, shader + accel_state->comp_vs_offset / 4);
/* comp ps --------------------------------------- */
accel_state->comp_ps_offset = 2560;
evergreen_comp_ps(ChipSet, shader + accel_state->comp_ps_offset / 4);
/* xv vs --------------------------------------- */
accel_state->xv_vs_offset = 3072;
evergreen_xv_vs(ChipSet, shader + accel_state->xv_vs_offset / 4);
/* xv ps --------------------------------------- */
accel_state->xv_ps_offset = 3584;
evergreen_xv_ps(ChipSet, shader + accel_state->xv_ps_offset / 4);
radeon_bo_unmap(accel_state->shaders_bo);
return TRUE;
}
static Bool
CAYMANLoadShaders(ScrnInfoPtr pScrn)
{
RADEONInfoPtr info = RADEONPTR(pScrn);
struct radeon_accel_state *accel_state = info->accel_state;
RADEONChipFamily ChipSet = info->ChipFamily;
uint32_t *shader;
int ret;
ret = radeon_bo_map(accel_state->shaders_bo, 1);
if (ret) {
FatalError("failed to map shader %d\n", ret);
return FALSE;
}
shader = accel_state->shaders_bo->ptr;
/* solid vs --------------------------------------- */
accel_state->solid_vs_offset = 0;
cayman_solid_vs(ChipSet, shader + accel_state->solid_vs_offset / 4);
/* solid ps --------------------------------------- */
accel_state->solid_ps_offset = 512;
cayman_solid_ps(ChipSet, shader + accel_state->solid_ps_offset / 4);
/* copy vs --------------------------------------- */
accel_state->copy_vs_offset = 1024;
cayman_copy_vs(ChipSet, shader + accel_state->copy_vs_offset / 4);
/* copy ps --------------------------------------- */
accel_state->copy_ps_offset = 1536;
cayman_copy_ps(ChipSet, shader + accel_state->copy_ps_offset / 4);
/* comp vs --------------------------------------- */
accel_state->comp_vs_offset = 2048;
cayman_comp_vs(ChipSet, shader + accel_state->comp_vs_offset / 4);
/* comp ps --------------------------------------- */
accel_state->comp_ps_offset = 2560;
cayman_comp_ps(ChipSet, shader + accel_state->comp_ps_offset / 4);
/* xv vs --------------------------------------- */
accel_state->xv_vs_offset = 3072;
cayman_xv_vs(ChipSet, shader + accel_state->xv_vs_offset / 4);
/* xv ps --------------------------------------- */
accel_state->xv_ps_offset = 3584;
cayman_xv_ps(ChipSet, shader + accel_state->xv_ps_offset / 4);
radeon_bo_unmap(accel_state->shaders_bo);
return TRUE;
}
Bool
EVERGREENDrawInit(ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
if (!info->accel_state->exa) {
xf86DrvMsg(pScreen->myNum, X_ERROR, "Memory map not set up\n");
return FALSE;
}
info->accel_state->exa->exa_major = EXA_VERSION_MAJOR;
info->accel_state->exa->exa_minor = EXA_VERSION_MINOR;
info->accel_state->exa->PrepareSolid = EVERGREENPrepareSolid;
info->accel_state->exa->Solid = EVERGREENSolid;
info->accel_state->exa->DoneSolid = EVERGREENDoneSolid;
info->accel_state->exa->PrepareCopy = EVERGREENPrepareCopy;
info->accel_state->exa->Copy = EVERGREENCopy;
info->accel_state->exa->DoneCopy = EVERGREENDoneCopy;
info->accel_state->exa->MarkSync = EVERGREENMarkSync;
info->accel_state->exa->WaitMarker = EVERGREENSync;
info->accel_state->exa->DestroyPixmap = RADEONEXADestroyPixmap;
info->accel_state->exa->PixmapIsOffscreen = RADEONEXAPixmapIsOffscreen;
info->accel_state->exa->PrepareAccess = RADEONPrepareAccess_CS;
info->accel_state->exa->FinishAccess = RADEONFinishAccess_CS;
info->accel_state->exa->UploadToScreen = EVERGREENUploadToScreen;
info->accel_state->exa->DownloadFromScreen = EVERGREENDownloadFromScreen;
info->accel_state->exa->CreatePixmap2 = RADEONEXACreatePixmap2;
info->accel_state->exa->SharePixmapBacking = RADEONEXASharePixmapBacking;
info->accel_state->exa->SetSharedPixmapBacking = RADEONEXASetSharedPixmapBacking;
info->accel_state->exa->flags = EXA_OFFSCREEN_PIXMAPS | EXA_SUPPORTS_PREPARE_AUX |
EXA_HANDLES_PIXMAPS | EXA_MIXED_PIXMAPS;
info->accel_state->exa->pixmapOffsetAlign = 256;
info->accel_state->exa->pixmapPitchAlign = 256;
info->accel_state->exa->CheckComposite = EVERGREENCheckComposite;
info->accel_state->exa->PrepareComposite = EVERGREENPrepareComposite;
info->accel_state->exa->Composite = EVERGREENComposite;
info->accel_state->exa->DoneComposite = EVERGREENDoneComposite;
info->accel_state->exa->maxPitchBytes = 32768;
info->accel_state->exa->maxX = 8192;
info->accel_state->exa->maxY = 8192;
/* not supported yet */
if (xf86ReturnOptValBool(info->Options, OPTION_EXA_VSYNC, FALSE)) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "EXA VSync enabled\n");
info->accel_state->vsync = TRUE;
} else
info->accel_state->vsync = FALSE;
if (!exaDriverInit(pScreen, info->accel_state->exa)) {
free(info->accel_state->exa);
return FALSE;
}
info->accel_state->XInited3D = FALSE;
info->accel_state->copy_area = NULL;
info->accel_state->src_obj[0].bo = NULL;
info->accel_state->src_obj[1].bo = NULL;
info->accel_state->dst_obj.bo = NULL;
info->accel_state->copy_area_bo = NULL;
info->accel_state->vbo.vb_start_op = -1;
info->accel_state->cbuf.vb_start_op = -1;
info->accel_state->finish_op = evergreen_finish_op;
info->accel_state->vbo.verts_per_op = 3;
info->accel_state->cbuf.verts_per_op = 1;
RADEONVlineHelperClear(pScrn);
radeon_vbo_init_lists(pScrn);
if (!EVERGREENAllocShaders(pScrn, pScreen))
return FALSE;
if (info->ChipFamily >= CHIP_FAMILY_CAYMAN) {
if (!CAYMANLoadShaders(pScrn))
return FALSE;
} else {
if (!EVERGREENLoadShaders(pScrn))
return FALSE;
}
exaMarkSync(pScreen);
return TRUE;
}