894 lines
25 KiB
C
894 lines
25 KiB
C
/**************************************************************************
|
|
*
|
|
* Copyright 2008 Red Hat Inc.
|
|
* All Rights Reserved.
|
|
*
|
|
* 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 VMWARE AND/OR ITS SUPPLIERS 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.
|
|
*
|
|
**************************************************************************/
|
|
|
|
|
|
#include "main/macros.h"
|
|
#include "main/mtypes.h"
|
|
#include "main/enums.h"
|
|
#include "main/fbobject.h"
|
|
#include "main/framebuffer.h"
|
|
#include "main/renderbuffer.h"
|
|
#include "main/context.h"
|
|
#include "swrast/swrast.h"
|
|
#include "drivers/common/meta.h"
|
|
#include "util/u_memory.h"
|
|
|
|
#include "radeon_common.h"
|
|
#include "radeon_mipmap_tree.h"
|
|
|
|
#define FILE_DEBUG_FLAG RADEON_TEXTURE
|
|
#define DBG(...) do { \
|
|
if (RADEON_DEBUG & FILE_DEBUG_FLAG) \
|
|
printf(__VA_ARGS__); \
|
|
} while(0)
|
|
|
|
static void
|
|
radeon_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
|
|
{
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(rb %p, rrb %p) \n",
|
|
__func__, rb, rrb);
|
|
|
|
assert(rrb);
|
|
|
|
if (rrb && rrb->bo) {
|
|
radeon_bo_unref(rrb->bo);
|
|
}
|
|
_mesa_delete_renderbuffer(ctx, rb);
|
|
}
|
|
|
|
#if defined(RADEON_R100)
|
|
static GLuint get_depth_z32(const struct radeon_renderbuffer * rrb,
|
|
GLint x, GLint y)
|
|
{
|
|
GLuint ba, address = 0;
|
|
|
|
ba = (y >> 4) * (rrb->pitch >> 6) + (x >> 4);
|
|
|
|
address |= (x & 0x7) << 2;
|
|
address |= (y & 0x3) << 5;
|
|
address |= (((x & 0x10) >> 2) ^ (y & 0x4)) << 5;
|
|
address |= (ba & 3) << 8;
|
|
address |= (y & 0x8) << 7;
|
|
address |= (((x & 0x8) << 1) ^ (y & 0x10)) << 7;
|
|
address |= (ba & ~0x3) << 10;
|
|
return address;
|
|
}
|
|
|
|
static GLuint get_depth_z16(const struct radeon_renderbuffer * rrb,
|
|
GLint x, GLint y)
|
|
{
|
|
GLuint ba, address = 0; /* a[0] = 0 */
|
|
|
|
ba = (y / 16) * (rrb->pitch >> 6) + (x / 32);
|
|
|
|
address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */
|
|
address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */
|
|
address |= (x & 0x8) << 4; /* a[7] = x[3] */
|
|
address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */
|
|
address |= (y & 0x8) << 7; /* a[10] = y[3] */
|
|
address |= ((x & 0x10) ^ (y & 0x10)) << 7;/* a[11] = x[4] ^ y[4] */
|
|
address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */
|
|
return address;
|
|
}
|
|
#endif
|
|
|
|
#if defined(RADEON_R200)
|
|
static GLuint get_depth_z32(const struct radeon_renderbuffer * rrb,
|
|
GLint x, GLint y)
|
|
{
|
|
GLuint offset;
|
|
GLuint b;
|
|
offset = 0;
|
|
b = (((y & 0x7ff) >> 4) * (rrb->pitch >> 7) + (x >> 5));
|
|
offset += (b >> 1) << 12;
|
|
offset += (((rrb->pitch >> 7) & 0x1) ? (b & 0x1) : ((b & 0x1) ^ ((y >> 4) & 0x1))) << 11;
|
|
offset += ((y >> 2) & 0x3) << 9;
|
|
offset += ((x >> 2) & 0x1) << 8;
|
|
offset += ((x >> 3) & 0x3) << 6;
|
|
offset += ((y >> 1) & 0x1) << 5;
|
|
offset += ((x >> 1) & 0x1) << 4;
|
|
offset += (y & 0x1) << 3;
|
|
offset += (x & 0x1) << 2;
|
|
|
|
return offset;
|
|
}
|
|
|
|
static GLuint get_depth_z16(const struct radeon_renderbuffer *rrb,
|
|
GLint x, GLint y)
|
|
{
|
|
GLuint offset;
|
|
GLuint b;
|
|
|
|
offset = 0;
|
|
b = (((y >> 4) * (rrb->pitch >> 7) + (x >> 6)));
|
|
offset += (b >> 1) << 12;
|
|
offset += (((rrb->pitch >> 7) & 0x1) ? (b & 0x1) : ((b & 0x1) ^ ((y >> 4) & 0x1))) << 11;
|
|
offset += ((y >> 2) & 0x3) << 9;
|
|
offset += ((x >> 3) & 0x1) << 8;
|
|
offset += ((x >> 4) & 0x3) << 6;
|
|
offset += ((x >> 2) & 0x1) << 5;
|
|
offset += ((y >> 1) & 0x1) << 4;
|
|
offset += ((x >> 1) & 0x1) << 3;
|
|
offset += (y & 0x1) << 2;
|
|
offset += (x & 0x1) << 1;
|
|
|
|
return offset;
|
|
}
|
|
#endif
|
|
|
|
static void
|
|
radeon_map_renderbuffer_s8z24(struct gl_renderbuffer *rb,
|
|
GLuint x, GLuint y, GLuint w, GLuint h,
|
|
GLbitfield mode,
|
|
GLubyte **out_map,
|
|
GLint *out_stride)
|
|
{
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
uint32_t *untiled_s8z24_map, *tiled_s8z24_map;
|
|
int ret;
|
|
int y_flip = (rb->Name == 0) ? -1 : 1;
|
|
int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0;
|
|
uint32_t pitch = w * rrb->cpp;
|
|
|
|
rrb->map_pitch = pitch;
|
|
|
|
rrb->map_buffer = malloc(w * h * 4);
|
|
ret = radeon_bo_map(rrb->bo, !!(mode & GL_MAP_WRITE_BIT));
|
|
assert(!ret);
|
|
(void) ret;
|
|
untiled_s8z24_map = rrb->map_buffer;
|
|
tiled_s8z24_map = rrb->bo->ptr;
|
|
|
|
for (uint32_t pix_y = 0; pix_y < h; ++ pix_y) {
|
|
for (uint32_t pix_x = 0; pix_x < w; ++pix_x) {
|
|
uint32_t flipped_y = y_flip * (int32_t)(y + pix_y) + y_bias;
|
|
uint32_t src_offset = get_depth_z32(rrb, x + pix_x, flipped_y);
|
|
uint32_t dst_offset = pix_y * rrb->map_pitch + pix_x * rrb->cpp;
|
|
untiled_s8z24_map[dst_offset/4] = tiled_s8z24_map[src_offset/4];
|
|
}
|
|
}
|
|
|
|
radeon_bo_unmap(rrb->bo);
|
|
|
|
*out_map = rrb->map_buffer;
|
|
*out_stride = rrb->map_pitch;
|
|
}
|
|
|
|
static void
|
|
radeon_map_renderbuffer_z16(struct gl_renderbuffer *rb,
|
|
GLuint x, GLuint y, GLuint w, GLuint h,
|
|
GLbitfield mode,
|
|
GLubyte **out_map,
|
|
GLint *out_stride)
|
|
{
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
uint16_t *untiled_z16_map, *tiled_z16_map;
|
|
int ret;
|
|
int y_flip = (rb->Name == 0) ? -1 : 1;
|
|
int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0;
|
|
uint32_t pitch = w * rrb->cpp;
|
|
|
|
rrb->map_pitch = pitch;
|
|
|
|
rrb->map_buffer = malloc(w * h * 2);
|
|
ret = radeon_bo_map(rrb->bo, !!(mode & GL_MAP_WRITE_BIT));
|
|
assert(!ret);
|
|
(void) ret;
|
|
|
|
untiled_z16_map = rrb->map_buffer;
|
|
tiled_z16_map = rrb->bo->ptr;
|
|
|
|
for (uint32_t pix_y = 0; pix_y < h; ++ pix_y) {
|
|
for (uint32_t pix_x = 0; pix_x < w; ++pix_x) {
|
|
uint32_t flipped_y = y_flip * (int32_t)(y + pix_y) + y_bias;
|
|
uint32_t src_offset = get_depth_z16(rrb, x + pix_x, flipped_y);
|
|
uint32_t dst_offset = pix_y * rrb->map_pitch + pix_x * rrb->cpp;
|
|
untiled_z16_map[dst_offset/2] = tiled_z16_map[src_offset/2];
|
|
}
|
|
}
|
|
|
|
radeon_bo_unmap(rrb->bo);
|
|
|
|
*out_map = rrb->map_buffer;
|
|
*out_stride = rrb->map_pitch;
|
|
}
|
|
|
|
static void
|
|
radeon_map_renderbuffer(struct gl_context *ctx,
|
|
struct gl_renderbuffer *rb,
|
|
GLuint x, GLuint y, GLuint w, GLuint h,
|
|
GLbitfield mode,
|
|
GLubyte **out_map,
|
|
GLint *out_stride,
|
|
bool flip_y)
|
|
{
|
|
struct radeon_context *const rmesa = RADEON_CONTEXT(ctx);
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
GLubyte *map;
|
|
GLboolean ok;
|
|
int stride, flip_stride;
|
|
int ret;
|
|
int src_x, src_y;
|
|
|
|
/* driver does not support GL_FRAMEBUFFER_FLIP_Y_MESA */
|
|
assert((rb->Name == 0) == flip_y);
|
|
|
|
if (!rrb || !rrb->bo) {
|
|
*out_map = NULL;
|
|
*out_stride = 0;
|
|
return;
|
|
}
|
|
|
|
rrb->map_mode = mode;
|
|
rrb->map_x = x;
|
|
rrb->map_y = y;
|
|
rrb->map_w = w;
|
|
rrb->map_h = h;
|
|
rrb->map_pitch = rrb->pitch;
|
|
|
|
ok = rmesa->vtbl.check_blit(rb->Format, rrb->pitch / rrb->cpp);
|
|
if (ok) {
|
|
if (rb->Name) {
|
|
src_x = x;
|
|
src_y = y;
|
|
} else {
|
|
src_x = x;
|
|
src_y = rrb->base.Base.Height - y - h;
|
|
}
|
|
|
|
/* Make a temporary buffer and blit the current contents of the renderbuffer
|
|
* out to it. This gives us linear access to the buffer, instead of having
|
|
* to do detiling in software.
|
|
*/
|
|
|
|
rrb->map_pitch = rrb->pitch;
|
|
|
|
assert(!rrb->map_bo);
|
|
rrb->map_bo = radeon_bo_open(rmesa->radeonScreen->bom, 0,
|
|
rrb->map_pitch * h, 4,
|
|
RADEON_GEM_DOMAIN_GTT, 0);
|
|
|
|
ok = rmesa->vtbl.blit(ctx, rrb->bo, rrb->draw_offset,
|
|
rb->Format, rrb->pitch / rrb->cpp,
|
|
rb->Width, rb->Height,
|
|
src_x, src_y,
|
|
rrb->map_bo, 0,
|
|
rb->Format, rrb->map_pitch / rrb->cpp,
|
|
w, h,
|
|
0, 0,
|
|
w, h,
|
|
GL_FALSE);
|
|
assert(ok);
|
|
|
|
ret = radeon_bo_map(rrb->map_bo, !!(mode & GL_MAP_WRITE_BIT));
|
|
assert(!ret);
|
|
|
|
map = rrb->map_bo->ptr;
|
|
|
|
if (rb->Name) {
|
|
*out_map = map;
|
|
*out_stride = rrb->map_pitch;
|
|
} else {
|
|
*out_map = map + (h - 1) * rrb->map_pitch;
|
|
*out_stride = -rrb->map_pitch;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* sw fallback flush stuff */
|
|
if (radeon_bo_is_referenced_by_cs(rrb->bo, rmesa->cmdbuf.cs)) {
|
|
radeon_firevertices(rmesa);
|
|
}
|
|
|
|
if ((rmesa->radeonScreen->chip_flags & RADEON_CHIPSET_DEPTH_ALWAYS_TILED) && !rrb->has_surface) {
|
|
if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT || rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT) {
|
|
radeon_map_renderbuffer_s8z24(rb, x, y, w, h,
|
|
mode, out_map, out_stride);
|
|
return;
|
|
}
|
|
if (rb->Format == MESA_FORMAT_Z_UNORM16) {
|
|
radeon_map_renderbuffer_z16(rb, x, y, w, h,
|
|
mode, out_map, out_stride);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ret = radeon_bo_map(rrb->bo, !!(mode & GL_MAP_WRITE_BIT));
|
|
assert(!ret);
|
|
(void) ret;
|
|
|
|
map = rrb->bo->ptr;
|
|
stride = rrb->map_pitch;
|
|
|
|
if (rb->Name == 0) {
|
|
y = rb->Height - 1 - y;
|
|
flip_stride = -stride;
|
|
} else {
|
|
flip_stride = stride;
|
|
map += rrb->draw_offset;
|
|
}
|
|
|
|
map += x * rrb->cpp;
|
|
map += (int)y * stride;
|
|
|
|
*out_map = map;
|
|
*out_stride = flip_stride;
|
|
}
|
|
|
|
static void
|
|
radeon_unmap_renderbuffer_s8z24(struct gl_context *ctx,
|
|
struct gl_renderbuffer *rb)
|
|
{
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
|
|
if (!rrb->map_buffer)
|
|
return;
|
|
|
|
if (rrb->map_mode & GL_MAP_WRITE_BIT) {
|
|
uint32_t *untiled_s8z24_map = rrb->map_buffer;
|
|
uint32_t *tiled_s8z24_map;
|
|
int y_flip = (rb->Name == 0) ? -1 : 1;
|
|
int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0;
|
|
|
|
radeon_bo_map(rrb->bo, 1);
|
|
|
|
tiled_s8z24_map = rrb->bo->ptr;
|
|
|
|
for (uint32_t pix_y = 0; pix_y < rrb->map_h; pix_y++) {
|
|
for (uint32_t pix_x = 0; pix_x < rrb->map_w; pix_x++) {
|
|
uint32_t flipped_y = y_flip * (int32_t)(pix_y + rrb->map_y) + y_bias;
|
|
uint32_t dst_offset = get_depth_z32(rrb, rrb->map_x + pix_x, flipped_y);
|
|
uint32_t src_offset = pix_y * rrb->map_pitch + pix_x * rrb->cpp;
|
|
tiled_s8z24_map[dst_offset/4] = untiled_s8z24_map[src_offset/4];
|
|
}
|
|
}
|
|
radeon_bo_unmap(rrb->bo);
|
|
}
|
|
free(rrb->map_buffer);
|
|
rrb->map_buffer = NULL;
|
|
}
|
|
|
|
static void
|
|
radeon_unmap_renderbuffer_z16(struct gl_context *ctx,
|
|
struct gl_renderbuffer *rb)
|
|
{
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
|
|
if (!rrb->map_buffer)
|
|
return;
|
|
|
|
if (rrb->map_mode & GL_MAP_WRITE_BIT) {
|
|
uint16_t *untiled_z16_map = rrb->map_buffer;
|
|
uint16_t *tiled_z16_map;
|
|
int y_flip = (rb->Name == 0) ? -1 : 1;
|
|
int y_bias = (rb->Name == 0) ? (rb->Height - 1) : 0;
|
|
|
|
radeon_bo_map(rrb->bo, 1);
|
|
|
|
tiled_z16_map = rrb->bo->ptr;
|
|
|
|
for (uint32_t pix_y = 0; pix_y < rrb->map_h; pix_y++) {
|
|
for (uint32_t pix_x = 0; pix_x < rrb->map_w; pix_x++) {
|
|
uint32_t flipped_y = y_flip * (int32_t)(pix_y + rrb->map_y) + y_bias;
|
|
uint32_t dst_offset = get_depth_z16(rrb, rrb->map_x + pix_x, flipped_y);
|
|
uint32_t src_offset = pix_y * rrb->map_pitch + pix_x * rrb->cpp;
|
|
tiled_z16_map[dst_offset/2] = untiled_z16_map[src_offset/2];
|
|
}
|
|
}
|
|
radeon_bo_unmap(rrb->bo);
|
|
}
|
|
free(rrb->map_buffer);
|
|
rrb->map_buffer = NULL;
|
|
}
|
|
|
|
|
|
static void
|
|
radeon_unmap_renderbuffer(struct gl_context *ctx,
|
|
struct gl_renderbuffer *rb)
|
|
{
|
|
struct radeon_context *const rmesa = RADEON_CONTEXT(ctx);
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
|
|
if ((rmesa->radeonScreen->chip_flags & RADEON_CHIPSET_DEPTH_ALWAYS_TILED) && !rrb->has_surface) {
|
|
if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT || rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT) {
|
|
radeon_unmap_renderbuffer_s8z24(ctx, rb);
|
|
return;
|
|
}
|
|
if (rb->Format == MESA_FORMAT_Z_UNORM16) {
|
|
radeon_unmap_renderbuffer_z16(ctx, rb);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!rrb->map_bo) {
|
|
if (rrb->bo)
|
|
radeon_bo_unmap(rrb->bo);
|
|
return;
|
|
}
|
|
|
|
radeon_bo_unmap(rrb->map_bo);
|
|
|
|
if (rrb->map_mode & GL_MAP_WRITE_BIT) {
|
|
GLboolean ok;
|
|
ok = rmesa->vtbl.blit(ctx, rrb->map_bo, 0,
|
|
rb->Format, rrb->map_pitch / rrb->cpp,
|
|
rrb->map_w, rrb->map_h,
|
|
0, 0,
|
|
rrb->bo, rrb->draw_offset,
|
|
rb->Format, rrb->pitch / rrb->cpp,
|
|
rb->Width, rb->Height,
|
|
rrb->map_x, rrb->map_y,
|
|
rrb->map_w, rrb->map_h,
|
|
GL_FALSE);
|
|
assert(ok);
|
|
(void) ok;
|
|
}
|
|
|
|
radeon_bo_unref(rrb->map_bo);
|
|
rrb->map_bo = NULL;
|
|
}
|
|
|
|
|
|
/**
|
|
* Called via glRenderbufferStorageEXT() to set the format and allocate
|
|
* storage for a user-created renderbuffer.
|
|
*/
|
|
static GLboolean
|
|
radeon_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
|
|
GLenum internalFormat,
|
|
GLuint width, GLuint height)
|
|
{
|
|
struct radeon_context *radeon = RADEON_CONTEXT(ctx);
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
uint32_t size, pitch;
|
|
int cpp;
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, rb %p) \n",
|
|
__func__, ctx, rb);
|
|
|
|
assert(rb->Name != 0);
|
|
switch (internalFormat) {
|
|
case GL_R3_G3_B2:
|
|
case GL_RGB4:
|
|
case GL_RGB5:
|
|
rb->Format = _radeon_texformat_rgb565;
|
|
cpp = 2;
|
|
break;
|
|
case GL_RGB:
|
|
case GL_RGB8:
|
|
case GL_RGB10:
|
|
case GL_RGB12:
|
|
case GL_RGB16:
|
|
rb->Format = _radeon_texformat_argb8888;
|
|
cpp = 4;
|
|
break;
|
|
case GL_RGBA:
|
|
case GL_RGBA2:
|
|
case GL_RGBA4:
|
|
case GL_RGB5_A1:
|
|
case GL_RGBA8:
|
|
case GL_RGB10_A2:
|
|
case GL_RGBA12:
|
|
case GL_RGBA16:
|
|
rb->Format = _radeon_texformat_argb8888;
|
|
cpp = 4;
|
|
break;
|
|
case GL_STENCIL_INDEX:
|
|
case GL_STENCIL_INDEX1_EXT:
|
|
case GL_STENCIL_INDEX4_EXT:
|
|
case GL_STENCIL_INDEX8_EXT:
|
|
case GL_STENCIL_INDEX16_EXT:
|
|
/* alloc a depth+stencil buffer */
|
|
rb->Format = MESA_FORMAT_Z24_UNORM_S8_UINT;
|
|
cpp = 4;
|
|
break;
|
|
case GL_DEPTH_COMPONENT16:
|
|
rb->Format = MESA_FORMAT_Z_UNORM16;
|
|
cpp = 2;
|
|
break;
|
|
case GL_DEPTH_COMPONENT:
|
|
case GL_DEPTH_COMPONENT24:
|
|
case GL_DEPTH_COMPONENT32:
|
|
rb->Format = MESA_FORMAT_Z24_UNORM_X8_UINT;
|
|
cpp = 4;
|
|
break;
|
|
case GL_DEPTH_STENCIL_EXT:
|
|
case GL_DEPTH24_STENCIL8_EXT:
|
|
rb->Format = MESA_FORMAT_Z24_UNORM_S8_UINT;
|
|
cpp = 4;
|
|
break;
|
|
default:
|
|
_mesa_problem(ctx,
|
|
"Unexpected format in radeon_alloc_renderbuffer_storage");
|
|
return GL_FALSE;
|
|
}
|
|
|
|
rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
|
|
|
|
if (ctx->Driver.Flush)
|
|
ctx->Driver.Flush(ctx, 0); /* +r6/r7 */
|
|
|
|
if (rrb->bo)
|
|
radeon_bo_unref(rrb->bo);
|
|
|
|
pitch = ((cpp * width + 63) & ~63) / cpp;
|
|
|
|
if (RADEON_DEBUG & RADEON_MEMORY)
|
|
fprintf(stderr,"Allocating %d x %d radeon RBO (pitch %d)\n", width,
|
|
height, pitch);
|
|
|
|
size = pitch * height * cpp;
|
|
rrb->pitch = pitch * cpp;
|
|
rrb->cpp = cpp;
|
|
rrb->bo = radeon_bo_open(radeon->radeonScreen->bom,
|
|
0,
|
|
size,
|
|
0,
|
|
RADEON_GEM_DOMAIN_VRAM,
|
|
0);
|
|
rb->Width = width;
|
|
rb->Height = height;
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static void
|
|
radeon_image_target_renderbuffer_storage(struct gl_context *ctx,
|
|
struct gl_renderbuffer *rb,
|
|
void *image_handle)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
struct radeon_renderbuffer *rrb;
|
|
__DRIscreen *screen;
|
|
__DRIimage *image;
|
|
|
|
screen = radeon->radeonScreen->driScreen;
|
|
image = screen->dri2.image->lookupEGLImage(screen, image_handle,
|
|
screen->loaderPrivate);
|
|
if (image == NULL)
|
|
return;
|
|
|
|
rrb = radeon_renderbuffer(rb);
|
|
|
|
if (ctx->Driver.Flush)
|
|
ctx->Driver.Flush(ctx, 0); /* +r6/r7 */
|
|
|
|
if (rrb->bo)
|
|
radeon_bo_unref(rrb->bo);
|
|
rrb->bo = image->bo;
|
|
radeon_bo_ref(rrb->bo);
|
|
fprintf(stderr, "image->bo: %p, name: %d, rbs: w %d -> p %d\n", image->bo, image->bo->handle,
|
|
image->width, image->pitch);
|
|
|
|
rrb->cpp = image->cpp;
|
|
rrb->pitch = image->pitch * image->cpp;
|
|
|
|
rb->Format = image->format;
|
|
rb->InternalFormat = image->internal_format;
|
|
rb->Width = image->width;
|
|
rb->Height = image->height;
|
|
rb->Format = image->format;
|
|
rb->_BaseFormat = _mesa_base_fbo_format(&radeon->glCtx,
|
|
image->internal_format);
|
|
rb->NeedsFinishRenderTexture = GL_TRUE;
|
|
}
|
|
|
|
/**
|
|
* Called for each hardware renderbuffer when a _window_ is resized.
|
|
* Just update fields.
|
|
* Not used for user-created renderbuffers!
|
|
*/
|
|
static GLboolean
|
|
radeon_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
|
|
GLenum internalFormat, GLuint width, GLuint height)
|
|
{
|
|
assert(rb->Name == 0);
|
|
rb->Width = width;
|
|
rb->Height = height;
|
|
rb->InternalFormat = internalFormat;
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, rb %p) \n",
|
|
__func__, ctx, rb);
|
|
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
/** Dummy function for gl_renderbuffer::AllocStorage() */
|
|
static GLboolean
|
|
radeon_nop_alloc_storage(struct gl_context * ctx,
|
|
UNUSED struct gl_renderbuffer *rb,
|
|
UNUSED GLenum internalFormat,
|
|
UNUSED GLuint width,
|
|
UNUSED GLuint height)
|
|
{
|
|
_mesa_problem(ctx, "radeon_op_alloc_storage should never be called.");
|
|
return GL_FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Create a renderbuffer for a window's color, depth and/or stencil buffer.
|
|
* Not used for user-created renderbuffers.
|
|
*/
|
|
struct radeon_renderbuffer *
|
|
radeon_create_renderbuffer(mesa_format format, __DRIdrawable *driDrawPriv)
|
|
{
|
|
struct radeon_renderbuffer *rrb;
|
|
struct gl_renderbuffer *rb;
|
|
|
|
rrb = CALLOC_STRUCT(radeon_renderbuffer);
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s( rrb %p ) \n",
|
|
__func__, rrb);
|
|
|
|
if (!rrb)
|
|
return NULL;
|
|
|
|
rb = &rrb->base.Base;
|
|
|
|
_mesa_init_renderbuffer(rb, 0);
|
|
rb->ClassID = RADEON_RB_CLASS;
|
|
rb->Format = format;
|
|
rb->_BaseFormat = _mesa_get_format_base_format(format);
|
|
rb->InternalFormat = _mesa_get_format_base_format(format);
|
|
|
|
rrb->dPriv = driDrawPriv;
|
|
|
|
rb->Delete = radeon_delete_renderbuffer;
|
|
rb->AllocStorage = radeon_alloc_window_storage;
|
|
|
|
rrb->bo = NULL;
|
|
return rrb;
|
|
}
|
|
|
|
static struct gl_renderbuffer *
|
|
radeon_new_renderbuffer(struct gl_context * ctx, GLuint name)
|
|
{
|
|
struct radeon_renderbuffer *rrb;
|
|
struct gl_renderbuffer *rb;
|
|
|
|
|
|
rrb = CALLOC_STRUCT(radeon_renderbuffer);
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, rrb %p) \n",
|
|
__func__, ctx, rrb);
|
|
|
|
if (!rrb)
|
|
return NULL;
|
|
|
|
rb = &rrb->base.Base;
|
|
|
|
_mesa_init_renderbuffer(rb, name);
|
|
rb->ClassID = RADEON_RB_CLASS;
|
|
rb->Delete = radeon_delete_renderbuffer;
|
|
rb->AllocStorage = radeon_alloc_renderbuffer_storage;
|
|
|
|
return rb;
|
|
}
|
|
|
|
static void
|
|
radeon_bind_framebuffer(struct gl_context * ctx, GLenum target,
|
|
struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
|
|
{
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, fb %p, target %s) \n",
|
|
__func__, ctx, fb,
|
|
_mesa_enum_to_string(target));
|
|
|
|
if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
|
|
radeon_draw_buffer(ctx, fb);
|
|
}
|
|
else {
|
|
/* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
|
|
}
|
|
}
|
|
|
|
static void
|
|
radeon_framebuffer_renderbuffer(struct gl_context * ctx,
|
|
struct gl_framebuffer *fb,
|
|
GLenum attachment, struct gl_renderbuffer *rb)
|
|
{
|
|
|
|
if (ctx->Driver.Flush)
|
|
ctx->Driver.Flush(ctx, 0); /* +r6/r7 */
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, fb %p, rb %p) \n",
|
|
__func__, ctx, fb, rb);
|
|
|
|
_mesa_FramebufferRenderbuffer_sw(ctx, fb, attachment, rb);
|
|
radeon_draw_buffer(ctx, fb);
|
|
}
|
|
|
|
static GLboolean
|
|
radeon_update_wrapper(struct gl_context *ctx, struct radeon_renderbuffer *rrb,
|
|
struct gl_texture_image *texImage)
|
|
{
|
|
struct gl_renderbuffer *rb = &rrb->base.Base;
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, rrb %p, texImage %p, texFormat %s) \n",
|
|
__func__, ctx, rrb, texImage, _mesa_get_format_name(texImage->TexFormat));
|
|
|
|
rrb->cpp = _mesa_get_format_bytes(texImage->TexFormat);
|
|
rrb->pitch = texImage->Width * rrb->cpp;
|
|
rb->Format = texImage->TexFormat;
|
|
rb->InternalFormat = texImage->InternalFormat;
|
|
rb->_BaseFormat = _mesa_get_format_base_format(rb->Format);
|
|
rb->Width = texImage->Width;
|
|
rb->Height = texImage->Height;
|
|
rb->Delete = radeon_delete_renderbuffer;
|
|
rb->AllocStorage = radeon_nop_alloc_storage;
|
|
|
|
return GL_TRUE;
|
|
}
|
|
|
|
static void
|
|
radeon_render_texture(struct gl_context * ctx,
|
|
struct gl_framebuffer *fb,
|
|
struct gl_renderbuffer_attachment *att)
|
|
{
|
|
struct gl_renderbuffer *rb = att->Renderbuffer;
|
|
struct gl_texture_image *newImage = rb->TexImage;
|
|
struct radeon_renderbuffer *rrb = radeon_renderbuffer(rb);
|
|
radeon_texture_image *radeon_image;
|
|
GLuint imageOffset;
|
|
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s(%p, fb %p, rrb %p, att %p)\n",
|
|
__func__, ctx, fb, rrb, att);
|
|
|
|
(void) fb;
|
|
|
|
assert(newImage);
|
|
|
|
radeon_image = (radeon_texture_image *)newImage;
|
|
|
|
if (!radeon_image->mt) {
|
|
/* Fallback on drawing to a texture without a miptree.
|
|
*/
|
|
_swrast_render_texture(ctx, fb, att);
|
|
return;
|
|
}
|
|
|
|
if (!radeon_update_wrapper(ctx, rrb, newImage)) {
|
|
_swrast_render_texture(ctx, fb, att);
|
|
return;
|
|
}
|
|
|
|
DBG("Begin render texture tex=%u w=%d h=%d refcount=%d\n",
|
|
att->Texture->Name, newImage->Width, newImage->Height,
|
|
rb->RefCount);
|
|
|
|
/* point the renderbufer's region to the texture image region */
|
|
if (rrb->bo != radeon_image->mt->bo) {
|
|
if (rrb->bo)
|
|
radeon_bo_unref(rrb->bo);
|
|
rrb->bo = radeon_image->mt->bo;
|
|
radeon_bo_ref(rrb->bo);
|
|
}
|
|
|
|
/* compute offset of the particular 2D image within the texture region */
|
|
imageOffset = radeon_miptree_image_offset(radeon_image->mt,
|
|
att->CubeMapFace,
|
|
att->TextureLevel);
|
|
|
|
if (att->Texture->Target == GL_TEXTURE_3D) {
|
|
imageOffset += radeon_image->mt->levels[att->TextureLevel].rowstride *
|
|
radeon_image->mt->levels[att->TextureLevel].height *
|
|
att->Zoffset;
|
|
}
|
|
|
|
/* store that offset in the region, along with the correct pitch for
|
|
* the image we are rendering to */
|
|
rrb->draw_offset = imageOffset;
|
|
rrb->pitch = radeon_image->mt->levels[att->TextureLevel].rowstride;
|
|
radeon_image->used_as_render_target = GL_TRUE;
|
|
|
|
/* update drawing region, etc */
|
|
radeon_draw_buffer(ctx, fb);
|
|
}
|
|
|
|
static void
|
|
radeon_finish_render_texture(struct gl_context *ctx, struct gl_renderbuffer *rb)
|
|
{
|
|
struct gl_texture_image *image = rb->TexImage;
|
|
radeon_texture_image *radeon_image = (radeon_texture_image *)image;
|
|
|
|
if (radeon_image)
|
|
radeon_image->used_as_render_target = GL_FALSE;
|
|
|
|
if (ctx->Driver.Flush)
|
|
ctx->Driver.Flush(ctx, 0); /* +r6/r7 */
|
|
}
|
|
static void
|
|
radeon_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
|
|
{
|
|
radeonContextPtr radeon = RADEON_CONTEXT(ctx);
|
|
mesa_format mesa_format;
|
|
int i;
|
|
|
|
for (i = -2; i < (GLint) ctx->Const.MaxColorAttachments; i++) {
|
|
struct gl_renderbuffer_attachment *att;
|
|
if (i == -2) {
|
|
att = &fb->Attachment[BUFFER_DEPTH];
|
|
} else if (i == -1) {
|
|
att = &fb->Attachment[BUFFER_STENCIL];
|
|
} else {
|
|
att = &fb->Attachment[BUFFER_COLOR0 + i];
|
|
}
|
|
|
|
if (att->Type == GL_TEXTURE) {
|
|
mesa_format = att->Renderbuffer->TexImage->TexFormat;
|
|
} else {
|
|
/* All renderbuffer formats are renderable, but not sampable */
|
|
continue;
|
|
}
|
|
|
|
if (!radeon->vtbl.is_format_renderable(mesa_format)){
|
|
fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED;
|
|
radeon_print(RADEON_TEXTURE, RADEON_TRACE,
|
|
"%s: HW doesn't support format %s as output format of attachment %d\n",
|
|
__func__, _mesa_get_format_name(mesa_format), i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void radeon_fbo_init(struct radeon_context *radeon)
|
|
{
|
|
radeon->glCtx.Driver.NewRenderbuffer = radeon_new_renderbuffer;
|
|
radeon->glCtx.Driver.MapRenderbuffer = radeon_map_renderbuffer;
|
|
radeon->glCtx.Driver.UnmapRenderbuffer = radeon_unmap_renderbuffer;
|
|
radeon->glCtx.Driver.BindFramebuffer = radeon_bind_framebuffer;
|
|
radeon->glCtx.Driver.FramebufferRenderbuffer = radeon_framebuffer_renderbuffer;
|
|
radeon->glCtx.Driver.RenderTexture = radeon_render_texture;
|
|
radeon->glCtx.Driver.FinishRenderTexture = radeon_finish_render_texture;
|
|
radeon->glCtx.Driver.ValidateFramebuffer = radeon_validate_framebuffer;
|
|
radeon->glCtx.Driver.BlitFramebuffer = _mesa_meta_and_swrast_BlitFramebuffer;
|
|
radeon->glCtx.Driver.EGLImageTargetRenderbufferStorage =
|
|
radeon_image_target_renderbuffer_storage;
|
|
}
|
|
|
|
|
|
void radeon_renderbuffer_set_bo(struct radeon_renderbuffer *rb,
|
|
struct radeon_bo *bo)
|
|
{
|
|
struct radeon_bo *old;
|
|
old = rb->bo;
|
|
rb->bo = bo;
|
|
radeon_bo_ref(bo);
|
|
if (old)
|
|
radeon_bo_unref(old);
|
|
}
|