summaryrefslogtreecommitdiff
path: root/src/gallium/drivers/r300/r300_texture.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/r300/r300_texture.c')
-rw-r--r--src/gallium/drivers/r300/r300_texture.c199
1 files changed, 136 insertions, 63 deletions
diff --git a/src/gallium/drivers/r300/r300_texture.c b/src/gallium/drivers/r300/r300_texture.c
index c0144f64b4..1b796257e4 100644
--- a/src/gallium/drivers/r300/r300_texture.c
+++ b/src/gallium/drivers/r300/r300_texture.c
@@ -31,8 +31,7 @@
#include "r300_texture.h"
#include "r300_screen.h"
#include "r300_state_inlines.h"
-
-#include "radeon_winsys.h"
+#include "r300_winsys.h"
#define TILE_WIDTH 0
#define TILE_HEIGHT 1
@@ -46,6 +45,18 @@ static const unsigned microblock_table[5][3][2] = {
{{ 2, 1}, {0, 0}, {0, 0}} /* 128 bits per pixel */
};
+/* Return true for non-compressed and non-YUV formats. */
+static boolean r300_format_is_plain(enum pipe_format format)
+{
+ const struct util_format_description *desc = util_format_description(format);
+
+ if (!format) {
+ return FALSE;
+ }
+
+ return desc->layout == UTIL_FORMAT_LAYOUT_PLAIN;
+}
+
/* Translate a pipe_format into a useful texture format for sampling.
*
* Some special formats are translated directly using R300_EASY_TX_FORMAT,
@@ -302,7 +313,6 @@ static uint32_t r300_translate_colorformat(enum pipe_format format)
case PIPE_FORMAT_A8_UNORM:
case PIPE_FORMAT_I8_UNORM:
case PIPE_FORMAT_L8_UNORM:
- case PIPE_FORMAT_L8_SRGB:
case PIPE_FORMAT_R8_UNORM:
case PIPE_FORMAT_R8_SNORM:
return R300_COLOR_FORMAT_I8;
@@ -311,24 +321,19 @@ static uint32_t r300_translate_colorformat(enum pipe_format format)
case PIPE_FORMAT_B5G6R5_UNORM:
return R300_COLOR_FORMAT_RGB565;
case PIPE_FORMAT_B5G5R5A1_UNORM:
+ case PIPE_FORMAT_B5G5R5X1_UNORM:
return R300_COLOR_FORMAT_ARGB1555;
case PIPE_FORMAT_B4G4R4A4_UNORM:
return R300_COLOR_FORMAT_ARGB4444;
/* 32-bit buffers. */
case PIPE_FORMAT_B8G8R8A8_UNORM:
- case PIPE_FORMAT_B8G8R8A8_SRGB:
case PIPE_FORMAT_B8G8R8X8_UNORM:
- case PIPE_FORMAT_B8G8R8X8_SRGB:
case PIPE_FORMAT_A8R8G8B8_UNORM:
- case PIPE_FORMAT_A8R8G8B8_SRGB:
case PIPE_FORMAT_X8R8G8B8_UNORM:
- case PIPE_FORMAT_X8R8G8B8_SRGB:
case PIPE_FORMAT_A8B8G8R8_UNORM:
case PIPE_FORMAT_R8G8B8A8_SNORM:
- case PIPE_FORMAT_A8B8G8R8_SRGB:
case PIPE_FORMAT_X8B8G8R8_UNORM:
- case PIPE_FORMAT_X8B8G8R8_SRGB:
case PIPE_FORMAT_R8SG8SB8UX8U_NORM:
return R300_COLOR_FORMAT_ARGB8888;
case PIPE_FORMAT_R10G10B10A2_UNORM:
@@ -393,12 +398,7 @@ static uint32_t r300_translate_out_fmt(enum pipe_format format)
desc = util_format_description(format);
/* Specifies how the shader output is written to the fog unit. */
- if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
- /* The gamma correction causes precision loss so we need
- * higher precision to maintain reasonable quality.
- * It has nothing to do with the colorbuffer format. */
- modifier |= R300_US_OUT_FMT_C4_10_GAMMA;
- } else if (desc->channel[0].type == UTIL_FORMAT_TYPE_FLOAT) {
+ if (desc->channel[0].type == UTIL_FORMAT_TYPE_FLOAT) {
if (desc->channel[0].size == 32) {
modifier |= R300_US_OUT_FMT_C4_32_FP;
} else {
@@ -428,46 +428,39 @@ static uint32_t r300_translate_out_fmt(enum pipe_format format)
return modifier | R300_C2_SEL_A;
case PIPE_FORMAT_I8_UNORM:
case PIPE_FORMAT_L8_UNORM:
- case PIPE_FORMAT_L8_SRGB:
case PIPE_FORMAT_R8_UNORM:
case PIPE_FORMAT_R8_SNORM:
return modifier | R300_C2_SEL_R;
- /* ARGB 32-bit outputs. */
+ /* BGRA outputs. */
case PIPE_FORMAT_B5G6R5_UNORM:
case PIPE_FORMAT_B5G5R5A1_UNORM:
+ case PIPE_FORMAT_B5G5R5X1_UNORM:
case PIPE_FORMAT_B4G4R4A4_UNORM:
case PIPE_FORMAT_B8G8R8A8_UNORM:
- case PIPE_FORMAT_B8G8R8A8_SRGB:
case PIPE_FORMAT_B8G8R8X8_UNORM:
- case PIPE_FORMAT_B8G8R8X8_SRGB:
return modifier |
R300_C0_SEL_B | R300_C1_SEL_G |
R300_C2_SEL_R | R300_C3_SEL_A;
- /* BGRA 32-bit outputs. */
+ /* ARGB outputs. */
case PIPE_FORMAT_A8R8G8B8_UNORM:
- case PIPE_FORMAT_A8R8G8B8_SRGB:
case PIPE_FORMAT_X8R8G8B8_UNORM:
- case PIPE_FORMAT_X8R8G8B8_SRGB:
return modifier |
R300_C0_SEL_A | R300_C1_SEL_R |
R300_C2_SEL_G | R300_C3_SEL_B;
- /* RGBA 32-bit outputs. */
+ /* ABGR outputs. */
case PIPE_FORMAT_A8B8G8R8_UNORM:
- case PIPE_FORMAT_R8G8B8A8_SNORM:
- case PIPE_FORMAT_A8B8G8R8_SRGB:
case PIPE_FORMAT_X8B8G8R8_UNORM:
- case PIPE_FORMAT_X8B8G8R8_SRGB:
return modifier |
R300_C0_SEL_A | R300_C1_SEL_B |
R300_C2_SEL_G | R300_C3_SEL_R;
- /* ABGR 32-bit outputs. */
+ /* RGBA outputs. */
+ case PIPE_FORMAT_R8G8B8A8_SNORM:
case PIPE_FORMAT_R8SG8SB8UX8U_NORM:
case PIPE_FORMAT_R10G10B10A2_UNORM:
- /* RGBA high precision outputs (same swizzles as ABGR low precision) */
case PIPE_FORMAT_R16G16B16A16_UNORM:
case PIPE_FORMAT_R16G16B16A16_SNORM:
//case PIPE_FORMAT_R16G16B16A16_FLOAT: /* not in pipe_format */
@@ -617,18 +610,23 @@ static unsigned r300_texture_get_tile_size(struct r300_texture* tex,
/* Return true if macrotiling should be enabled on the miplevel. */
static boolean r300_texture_macro_switch(struct r300_texture *tex,
unsigned level,
- boolean rv350_mode)
+ boolean rv350_mode,
+ int dim)
{
- unsigned tile_width, width;
+ unsigned tile, texdim;
- tile_width = r300_texture_get_tile_size(tex, TILE_WIDTH, TRUE);
- width = u_minify(tex->tex.width0, level);
+ tile = r300_texture_get_tile_size(tex, dim, TRUE);
+ if (dim == TILE_WIDTH) {
+ texdim = u_minify(tex->tex.width0, level);
+ } else {
+ texdim = u_minify(tex->tex.height0, level);
+ }
/* See TX_FILTER1_n.MACRO_SWITCH. */
if (rv350_mode) {
- return width >= tile_width;
+ return texdim >= tile;
} else {
- return width > tile_width;
+ return texdim > tile;
}
}
@@ -653,7 +651,7 @@ unsigned r300_texture_get_stride(struct r300_screen* screen,
width = u_minify(tex->tex.width0, level);
- if (!util_format_is_compressed(tex->tex.format)) {
+ if (r300_format_is_plain(tex->tex.format)) {
tile_width = r300_texture_get_tile_size(tex, TILE_WIDTH,
tex->mip_macrotile[level]);
width = align(width, tile_width);
@@ -671,7 +669,7 @@ static unsigned r300_texture_get_nblocksy(struct r300_texture* tex,
height = u_minify(tex->tex.height0, level);
- if (!util_format_is_compressed(tex->tex.format)) {
+ if (r300_format_is_plain(tex->tex.format)) {
tile_height = r300_texture_get_tile_size(tex, TILE_HEIGHT,
tex->mip_macrotile[level]);
height = align(height, tile_height);
@@ -692,9 +690,10 @@ static void r300_setup_miptree(struct r300_screen* screen,
for (i = 0; i <= base->last_level; i++) {
/* Let's see if this miplevel can be macrotiled. */
- tex->mip_macrotile[i] = (tex->macrotile == R300_BUFFER_TILED &&
- r300_texture_macro_switch(tex, i, rv350_mode)) ?
- R300_BUFFER_TILED : R300_BUFFER_LINEAR;
+ tex->mip_macrotile[i] =
+ (tex->macrotile == R300_BUFFER_TILED &&
+ r300_texture_macro_switch(tex, i, rv350_mode, TILE_WIDTH)) ?
+ R300_BUFFER_TILED : R300_BUFFER_LINEAR;
stride = r300_texture_get_stride(screen, tex, i);
nblocksy = r300_texture_get_nblocksy(tex, i);
@@ -724,14 +723,51 @@ static void r300_setup_flags(struct r300_texture* tex)
!util_is_power_of_two(tex->tex.height0);
}
+static void r300_setup_tiling(struct pipe_screen *screen,
+ struct r300_texture *tex)
+{
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen *)screen->winsys;
+ enum pipe_format format = tex->tex.format;
+ boolean rv350_mode = r300_screen(screen)->caps->family >= CHIP_FAMILY_RV350;
+
+ if (!r300_format_is_plain(format)) {
+ return;
+ }
+
+ if (tex->tex.width0 == 1 ||
+ tex->tex.height0 == 1) {
+ return;
+ }
+
+ /* Set microtiling. */
+ switch (util_format_get_blocksize(format)) {
+ case 1:
+ case 4:
+ tex->microtile = R300_BUFFER_TILED;
+ break;
+
+ case 2:
+ case 8:
+ if (rws->get_value(rws, R300_VID_SQUARE_TILING_SUPPORT)) {
+ tex->microtile = R300_BUFFER_SQUARETILED;
+ }
+ break;
+ }
+
+ /* Set macrotiling. */
+ if (r300_texture_macro_switch(tex, 0, rv350_mode, TILE_WIDTH) &&
+ r300_texture_macro_switch(tex, 0, rv350_mode, TILE_HEIGHT)) {
+ tex->macrotile = R300_BUFFER_TILED;
+ }
+}
+
/* Create a new texture. */
-static struct pipe_texture*
- r300_texture_create(struct pipe_screen* screen,
- const struct pipe_texture* template)
+static struct pipe_texture* r300_texture_create(struct pipe_screen* screen,
+ const struct pipe_texture* template)
{
struct r300_texture* tex = CALLOC_STRUCT(r300_texture);
struct r300_screen* rscreen = r300_screen(screen);
- struct radeon_winsys* winsys = (struct radeon_winsys*)screen->winsys;
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen *)screen->winsys;
if (!tex) {
return NULL;
@@ -742,16 +778,19 @@ static struct pipe_texture*
tex->tex.screen = screen;
r300_setup_flags(tex);
+ if (!(template->tex_usage & R300_TEXTURE_USAGE_TRANSFER)) {
+ r300_setup_tiling(screen, tex);
+ }
r300_setup_miptree(rscreen, tex);
r300_setup_texture_state(rscreen, tex);
- tex->buffer = screen->buffer_create(screen, 2048,
- PIPE_BUFFER_USAGE_PIXEL,
- tex->size);
- winsys->buffer_set_tiling(winsys, tex->buffer,
- tex->pitch[0],
- tex->microtile != R300_BUFFER_LINEAR,
- tex->macrotile != R300_BUFFER_LINEAR);
+ tex->buffer = rws->buffer_create(rws, 2048,
+ PIPE_BUFFER_USAGE_PIXEL,
+ tex->size);
+ rws->buffer_set_tiling(rws, tex->buffer,
+ tex->pitch[0],
+ tex->microtile,
+ tex->macrotile);
if (!tex->buffer) {
FREE(tex);
@@ -764,9 +803,9 @@ static struct pipe_texture*
static void r300_texture_destroy(struct pipe_texture* texture)
{
struct r300_texture* tex = (struct r300_texture*)texture;
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen *)texture->screen->winsys;
- pipe_buffer_reference(&tex->buffer, NULL);
-
+ rws->buffer_reference(rws, &tex->buffer, NULL);
FREE(tex);
}
@@ -806,14 +845,17 @@ static void r300_tex_surface_destroy(struct pipe_surface* s)
FREE(s);
}
+
static struct pipe_texture*
- r300_texture_blanket(struct pipe_screen* screen,
- const struct pipe_texture* base,
- const unsigned* stride,
- struct pipe_buffer* buffer)
+ r300_texture_from_handle(struct pipe_screen* screen,
+ const struct pipe_texture* base,
+ struct winsys_handle *whandle)
{
- struct r300_texture* tex;
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen*)screen->winsys;
struct r300_screen* rscreen = r300_screen(screen);
+ struct r300_winsys_buffer *buffer;
+ struct r300_texture* tex;
+ unsigned stride;
/* Support only 2D textures without mipmaps */
if (base->target != PIPE_TEXTURE_2D ||
@@ -822,6 +864,11 @@ static struct pipe_texture*
return NULL;
}
+ buffer = rws->buffer_from_handle(rws, screen, whandle, &stride);
+ if (!buffer) {
+ return NULL;
+ }
+
tex = CALLOC_STRUCT(r300_texture);
if (!tex) {
return NULL;
@@ -831,17 +878,38 @@ static struct pipe_texture*
pipe_reference_init(&tex->tex.reference, 1);
tex->tex.screen = screen;
- tex->stride_override = *stride;
- tex->pitch[0] = *stride / util_format_get_blocksize(base->format);
+ tex->stride_override = stride;
+ tex->pitch[0] = stride / util_format_get_blocksize(base->format);
r300_setup_flags(tex);
r300_setup_texture_state(rscreen, tex);
- pipe_buffer_reference(&tex->buffer, buffer);
+ /* one ref already taken */
+ tex->buffer = buffer;
return (struct pipe_texture*)tex;
}
+static boolean
+ r300_texture_get_handle(struct pipe_screen* screen,
+ struct pipe_texture *texture,
+ struct winsys_handle *whandle)
+{
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen *)screen->winsys;
+ struct r300_texture* tex = (struct r300_texture*)texture;
+ unsigned stride;
+
+ if (!tex) {
+ return FALSE;
+ }
+
+ stride = r300_texture_get_stride(r300_screen(screen), tex, 0);
+
+ rws->buffer_get_handle(rws, tex->buffer, stride, whandle);
+
+ return TRUE;
+}
+
static struct pipe_video_surface *
r300_video_surface_create(struct pipe_screen *screen,
enum pipe_video_chroma_format chroma_format,
@@ -893,10 +961,11 @@ static void r300_video_surface_destroy(struct pipe_video_surface *vsfc)
void r300_init_screen_texture_functions(struct pipe_screen* screen)
{
screen->texture_create = r300_texture_create;
+ screen->texture_from_handle = r300_texture_from_handle;
+ screen->texture_get_handle = r300_texture_get_handle;
screen->texture_destroy = r300_texture_destroy;
screen->get_tex_surface = r300_get_tex_surface;
screen->tex_surface_destroy = r300_tex_surface_destroy;
- screen->texture_blanket = r300_texture_blanket;
screen->video_surface_create = r300_video_surface_create;
screen->video_surface_destroy= r300_video_surface_destroy;
@@ -904,19 +973,23 @@ void r300_init_screen_texture_functions(struct pipe_screen* screen)
boolean r300_get_texture_buffer(struct pipe_screen* screen,
struct pipe_texture* texture,
- struct pipe_buffer** buffer,
+ struct r300_winsys_buffer** buffer,
unsigned* stride)
{
struct r300_texture* tex = (struct r300_texture*)texture;
+ struct r300_winsys_screen *rws = (struct r300_winsys_screen *)screen->winsys;
+ struct r300_winsys_buffer *buf;
+
if (!tex) {
return FALSE;
}
- pipe_buffer_reference(buffer, tex->buffer);
+ rws->buffer_reference(rws, &buf, tex->buffer);
if (stride) {
*stride = r300_texture_get_stride(r300_screen(screen), tex, 0);
}
+ *buffer = buf;
return TRUE;
}