mesa: Pure software accum buffer.

The existing implementation was already implemented on software, but relied
on the pipe driver to always support the R16G16B16A16_SNORM format. This
patch eliminates that, without prejudice against a future hardware-only
implementation.

It also avoids some of the short <-> float conversions, and only does a read
transfer of the color buffer on GL_RETURN if absolutely necessary.
This commit is contained in:
José Fonseca
2009-06-10 15:39:02 +01:00
parent 8bfbb7ec8b
commit 52411a1951
4 changed files with 188 additions and 235 deletions

View File

@@ -48,10 +48,6 @@
#include "util/u_tile.h"
#define UNCLAMPED_FLOAT_TO_SHORT(us, f) \
us = ( (short) ( CLAMP((f), -1.0, 1.0) * 32767.0F) )
/**
* For hardware that supports deep color buffers, we could accelerate
* most/all the accum operations with blending/texturing.
@@ -59,74 +55,20 @@
*/
/**
* Wrapper for pipe_get_tile_rgba(). Do format/cpp override to make the
* tile util function think the surface is 16bit/channel, even if it's not.
* See also: st_renderbuffer_alloc_storage()
*/
static void
acc_get_tile_rgba(struct pipe_context *pipe, struct pipe_transfer *acc_pt,
uint x, uint y, uint w, uint h, float *p)
{
const enum pipe_format f = acc_pt->format;
const struct pipe_format_block b = acc_pt->block;
acc_pt->format = DEFAULT_ACCUM_PIPE_FORMAT;
acc_pt->block.size = 8;
acc_pt->block.width = 1;
acc_pt->block.height = 1;
pipe_get_tile_rgba(acc_pt, x, y, w, h, p);
acc_pt->format = f;
acc_pt->block = b;
}
/**
* Wrapper for pipe_put_tile_rgba(). Do format/cpp override to make the
* tile util function think the surface is 16bit/channel, even if it's not.
* See also: st_renderbuffer_alloc_storage()
*/
static void
acc_put_tile_rgba(struct pipe_context *pipe, struct pipe_transfer *acc_pt,
uint x, uint y, uint w, uint h, const float *p)
{
enum pipe_format f = acc_pt->format;
const struct pipe_format_block b = acc_pt->block;
acc_pt->format = DEFAULT_ACCUM_PIPE_FORMAT;
acc_pt->block.size = 8;
acc_pt->block.width = 1;
acc_pt->block.height = 1;
pipe_put_tile_rgba(acc_pt, x, y, w, h, p);
acc_pt->format = f;
acc_pt->block = b;
}
void
st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
{
struct st_renderbuffer *acc_strb = st_renderbuffer(rb);
struct pipe_transfer *acc_pt;
struct pipe_screen *screen = ctx->st->pipe->screen;
const GLint xpos = ctx->DrawBuffer->_Xmin;
const GLint ypos = ctx->DrawBuffer->_Ymin;
const GLint width = ctx->DrawBuffer->_Xmax - xpos;
const GLint height = ctx->DrawBuffer->_Ymax - ypos;
GLubyte *map;
size_t stride = acc_strb->stride;
GLubyte *data = acc_strb->data;
acc_pt = st_cond_flush_get_tex_transfer(st_context(ctx), acc_strb->texture,
0, 0, 0,
PIPE_TRANSFER_WRITE, xpos, ypos,
width, height);
map = screen->transfer_map(screen, acc_pt);
if(!data)
return;
/* note acc_strb->format might not equal acc_pt->format */
switch (acc_strb->format) {
case PIPE_FORMAT_R16G16B16A16_SNORM:
{
@@ -136,7 +78,7 @@ st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
GLshort a = FLOAT_TO_SHORT(ctx->Accum.ClearColor[3]);
int i, j;
for (i = 0; i < height; i++) {
GLshort *dst = (GLshort *) (map + i * acc_pt->stride + xpos * 8);
GLshort *dst = (GLshort *) (data + (ypos + i) * stride + xpos * 8);
for (j = 0; j < width; j++) {
dst[0] = r;
dst[1] = g;
@@ -150,9 +92,6 @@ st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
default:
_mesa_problem(ctx, "unexpected format in st_clear_accum_buffer()");
}
screen->transfer_unmap(screen, acc_pt);
screen->tex_transfer_destroy(acc_pt);
}
@@ -162,27 +101,18 @@ accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
GLint xpos, GLint ypos, GLint width, GLint height,
struct st_renderbuffer *acc_strb)
{
struct pipe_screen *screen = ctx->st->pipe->screen;
struct pipe_transfer *acc_pt;
GLubyte *map;
size_t stride = acc_strb->stride;
GLubyte *data = acc_strb->data;
acc_pt = st_cond_flush_get_tex_transfer(st_context(ctx), acc_strb->texture,
0, 0, 0,
PIPE_TRANSFER_READ_WRITE,
xpos, ypos,
width, height);
map = screen->transfer_map(screen, acc_pt);
/* note acc_strb->format might not equal acc_pt->format */
switch (acc_strb->format) {
case PIPE_FORMAT_R16G16B16A16_SNORM:
{
int i, j;
for (i = 0; i < height; i++) {
GLshort *acc = (GLshort *) (map + (ypos + i) * acc_pt->stride + xpos * 8);
GLshort *acc = (GLshort *) (data + (ypos + i) * stride + xpos * 8);
for (j = 0; j < width * 4; j++) {
float val = SHORT_TO_FLOAT(acc[j]) * scale + bias;
acc[j] = FLOAT_TO_SHORT(val);
float val = SHORT_TO_FLOAT(*acc) * scale + bias;
*acc++ = FLOAT_TO_SHORT(val);
}
}
}
@@ -190,9 +120,6 @@ accum_mad(GLcontext *ctx, GLfloat scale, GLfloat bias,
default:
_mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
}
screen->transfer_unmap(screen, acc_pt);
screen->tex_transfer_destroy(acc_pt);
}
@@ -204,39 +131,39 @@ accum_accum(struct st_context *st, GLfloat value,
{
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct pipe_transfer *acc_trans, *color_trans;
GLfloat *colorBuf, *accBuf;
GLint i;
acc_trans = st_cond_flush_get_tex_transfer(st, acc_strb->texture, 0, 0, 0,
PIPE_TRANSFER_READ, xpos, ypos,
width, height);
struct pipe_transfer *color_trans;
size_t stride = acc_strb->stride;
GLubyte *data = acc_strb->data;
GLfloat *buf;
color_trans = st_cond_flush_get_tex_transfer(st, color_strb->texture,
0, 0, 0,
PIPE_TRANSFER_READ, xpos, ypos,
width, height);
colorBuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
accBuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
pipe_get_tile_rgba(color_trans, 0, 0, width, height, colorBuf);
acc_get_tile_rgba(pipe, acc_trans, 0, 0, width, height, accBuf);
pipe_get_tile_rgba(color_trans, 0, 0, width, height, buf);
for (i = 0; i < 4 * width * height; i++) {
accBuf[i] = accBuf[i] + colorBuf[i] * value;
switch (acc_strb->format) {
case PIPE_FORMAT_R16G16B16A16_SNORM:
{
const GLfloat *color = buf;
int i, j;
for (i = 0; i < height; i++) {
GLshort *acc = (GLshort *) (data + (ypos + i) * stride + xpos * 8);
for (j = 0; j < width * 4; j++) {
float val = *color++ * value;
*acc++ += FLOAT_TO_SHORT(val);
}
}
}
break;
default:
_mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
}
screen->tex_transfer_destroy(acc_trans);
acc_trans = st_no_flush_get_tex_transfer(st, acc_strb->texture, 0, 0, 0,
PIPE_TRANSFER_WRITE, xpos, ypos,
width, height);
acc_put_tile_rgba(pipe, acc_trans, 0, 0, width, height, accBuf);
_mesa_free(colorBuf);
_mesa_free(accBuf);
screen->tex_transfer_destroy(acc_trans);
_mesa_free(buf);
screen->tex_transfer_destroy(color_trans);
}
@@ -249,13 +176,10 @@ accum_load(struct st_context *st, GLfloat value,
{
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct pipe_transfer *acc_trans, *color_trans;
struct pipe_transfer *color_trans;
size_t stride = acc_strb->stride;
GLubyte *data = acc_strb->data;
GLfloat *buf;
GLint i;
acc_trans = st_cond_flush_get_tex_transfer(st, acc_strb->texture, 0, 0, 0,
PIPE_TRANSFER_WRITE, xpos, ypos,
width, height);
color_trans = st_cond_flush_get_tex_transfer(st, color_strb->texture,
0, 0, 0,
@@ -266,14 +190,25 @@ accum_load(struct st_context *st, GLfloat value,
pipe_get_tile_rgba(color_trans, 0, 0, width, height, buf);
for (i = 0; i < 4 * width * height; i++) {
buf[i] = buf[i] * value;
switch (acc_strb->format) {
case PIPE_FORMAT_R16G16B16A16_SNORM:
{
const GLfloat *color = buf;
int i, j;
for (i = 0; i < height; i++) {
GLshort *acc = (GLshort *) (data + (ypos + i) * stride + xpos * 8);
for (j = 0; j < width * 4; j++) {
float val = *color++ * value;
*acc++ = FLOAT_TO_SHORT(val);
}
}
}
break;
default:
_mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
}
acc_put_tile_rgba(pipe, acc_trans, 0, 0, width, height, buf);
_mesa_free(buf);
screen->tex_transfer_destroy(acc_trans);
screen->tex_transfer_destroy(color_trans);
}
@@ -287,48 +222,58 @@ accum_return(GLcontext *ctx, GLfloat value,
struct pipe_context *pipe = ctx->st->pipe;
struct pipe_screen *screen = pipe->screen;
const GLubyte *colormask = ctx->Color.ColorMask;
struct pipe_transfer *acc_trans, *color_trans;
GLfloat *abuf, *cbuf = NULL;
GLint i, ch;
enum pipe_transfer_usage usage;
struct pipe_transfer *color_trans;
size_t stride = acc_strb->stride;
const GLubyte *data = acc_strb->data;
GLfloat *buf;
abuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
buf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
acc_trans = st_cond_flush_get_tex_transfer(st_context(ctx),
acc_strb->texture, 0, 0, 0,
PIPE_TRANSFER_READ, xpos, ypos,
width, height);
if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3])
usage = PIPE_TRANSFER_READ_WRITE;
else
usage = PIPE_TRANSFER_WRITE;
color_trans = st_cond_flush_get_tex_transfer(st_context(ctx),
color_strb->texture, 0, 0, 0,
PIPE_TRANSFER_READ_WRITE,
usage,
xpos, ypos,
width, height);
acc_get_tile_rgba(pipe, acc_trans, 0, 0, width, height, abuf);
if (usage != PIPE_TRANSFER_WRITE)
pipe_get_tile_rgba(color_trans, 0, 0, width, height, buf);
if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) {
cbuf = (GLfloat *) _mesa_malloc(width * height * 4 * sizeof(GLfloat));
pipe_get_tile_rgba(color_trans, 0, 0, width, height, cbuf);
}
for (i = 0; i < width * height; i++) {
switch (acc_strb->format) {
case PIPE_FORMAT_R16G16B16A16_SNORM:
{
GLfloat *color = buf;
int i, j, ch;
for (i = 0; i < height; i++) {
const GLshort *acc = (const GLshort *) (data + (ypos + i) * stride + xpos * 8);
for (j = 0; j < width; j++) {
for (ch = 0; ch < 4; ch++) {
if (colormask[ch]) {
GLfloat val = abuf[i * 4 + ch] * value;
abuf[i * 4 + ch] = CLAMP(val, 0.0f, 1.0f);
GLfloat val = SHORT_TO_FLOAT(*acc * value);
*color = CLAMP(val, 0.0f, 1.0f);
}
else {
abuf[i * 4 + ch] = cbuf[i * 4 + ch];
/* No change */
}
++acc;
++color;
}
}
}
}
break;
default:
_mesa_problem(NULL, "unexpected format in st_clear_accum_buffer()");
}
pipe_put_tile_rgba(color_trans, 0, 0, width, height, abuf);
pipe_put_tile_rgba(color_trans, 0, 0, width, height, buf);
_mesa_free(abuf);
if (cbuf)
_mesa_free(cbuf);
screen->tex_transfer_destroy(acc_trans);
_mesa_free(buf);
screen->tex_transfer_destroy(color_trans);
}
@@ -347,6 +292,9 @@ st_Accum(GLcontext *ctx, GLenum op, GLfloat value)
const GLint width = ctx->DrawBuffer->_Xmax - xpos;
const GLint height = ctx->DrawBuffer->_Ymax - ypos;
if(!acc_strb->data)
return;
/* make sure color bufs aren't cached */
st_flush( st, PIPE_FLUSH_RENDER_CACHE, NULL );

View File

@@ -88,6 +88,35 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
{
struct pipe_context *pipe = ctx->st->pipe;
struct st_renderbuffer *strb = st_renderbuffer(rb);
enum pipe_format format;
if (strb->format != PIPE_FORMAT_NONE)
format = strb->format;
else
format = st_choose_renderbuffer_format(pipe, internalFormat);
/* init renderbuffer fields */
strb->Base.Width = width;
strb->Base.Height = height;
init_renderbuffer_bits(strb, format);
if(strb->software) {
struct pipe_format_block block;
size_t size;
_mesa_free(strb->data);
assert(strb->format != PIPE_FORMAT_NONE);
pf_get_block(strb->format, &block);
strb->stride = pf_get_stride(&block, width);
size = pf_get_2d_size(&block, strb->stride, height);
strb->data = _mesa_malloc(size);
return strb->data != NULL;
}
else {
struct pipe_texture template;
unsigned surface_usage;
@@ -100,19 +129,14 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
*/
memset(&template, 0, sizeof(template));
template.target = PIPE_TEXTURE_2D;
if (strb->format != PIPE_FORMAT_NONE) {
template.format = strb->format;
}
else {
template.format = st_choose_renderbuffer_format(pipe, internalFormat);
}
pf_get_block(template.format, &template.block);
template.format = format;
pf_get_block(format, &template.block);
template.width[0] = width;
template.height[0] = height;
template.depth[0] = 1;
template.last_level = 0;
template.nr_samples = rb->NumSamples;
if (pf_is_depth_stencil(template.format)) {
if (pf_is_depth_stencil(format)) {
template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
}
else {
@@ -120,11 +144,6 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
PIPE_TEXTURE_USAGE_RENDER_TARGET);
}
/* init renderbuffer fields */
strb->Base.Width = width;
strb->Base.Height = height;
init_renderbuffer_bits(strb, template.format);
/* Probably need dedicated flags for surface usage too:
*/
surface_usage = (PIPE_BUFFER_USAGE_GPU_READ |
@@ -137,27 +156,6 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
strb->texture = pipe->screen->texture_create( pipe->screen,
&template );
/* Special path for accum buffers.
*
* Try a different surface format. Since accum buffers are s/w
* only for now, the surface pixel format doesn't really matter,
* only that the buffer is large enough.
*/
if (!strb->texture && template.format == DEFAULT_ACCUM_PIPE_FORMAT)
{
/* Actually, just setting this usage value should be sufficient
* to tell the driver to go ahead and allocate the buffer, even
* if HW doesn't support the format.
*/
template.tex_usage = 0;
surface_usage = (PIPE_BUFFER_USAGE_CPU_READ |
PIPE_BUFFER_USAGE_CPU_WRITE);
strb->texture = pipe->screen->texture_create( pipe->screen,
&template );
}
if (!strb->texture)
return FALSE;
@@ -174,6 +172,7 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
return strb->surface != NULL;
}
}
/**
@@ -186,6 +185,7 @@ st_renderbuffer_delete(struct gl_renderbuffer *rb)
ASSERT(strb);
pipe_surface_reference(&strb->surface, NULL);
pipe_texture_reference(&strb->texture, NULL);
_mesa_free(strb->data);
_mesa_free(strb);
}
@@ -242,7 +242,7 @@ st_new_renderbuffer(GLcontext *ctx, GLuint name)
* renderbuffer). The window system code determines the format.
*/
struct gl_renderbuffer *
st_new_renderbuffer_fb(enum pipe_format format, int samples)
st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
{
struct st_renderbuffer *strb;
@@ -256,6 +256,7 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples)
strb->Base.ClassID = 0x4242; /* just a unique value */
strb->Base.NumSamples = samples;
strb->format = format;
strb->software = sw;
switch (format) {
case PIPE_FORMAT_A8R8G8B8_UNORM:
@@ -287,7 +288,7 @@ st_new_renderbuffer_fb(enum pipe_format format, int samples)
strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
strb->Base._BaseFormat = GL_STENCIL_INDEX;
break;
case DEFAULT_ACCUM_PIPE_FORMAT: /*PIPE_FORMAT_R16G16B16A16_SNORM*/
case PIPE_FORMAT_R16G16B16A16_SNORM:
strb->Base.InternalFormat = GL_RGBA16;
strb->Base._BaseFormat = GL_RGBA;
break;

View File

@@ -30,10 +30,6 @@
#define ST_CB_FBO_H
#define DEFAULT_ACCUM_PIPE_FORMAT PIPE_FORMAT_R16G16B16A16_SNORM
/**
* Derived renderbuffer class. Just need to add a pointer to the
* pipe surface.
@@ -45,6 +41,13 @@ struct st_renderbuffer
struct pipe_surface *surface; /* temporary view into texture */
enum pipe_format format; /** preferred format, or PIPE_FORMAT_NONE */
/**
* Used only when hardware accumulation buffers are not supported.
*/
boolean software;
size_t stride;
void *data;
struct st_texture_object *rtt; /**< GL render to texture's texture */
int rtt_level, rtt_face, rtt_slice;
@@ -62,7 +65,7 @@ st_renderbuffer(struct gl_renderbuffer *rb)
extern struct gl_renderbuffer *
st_new_renderbuffer_fb(enum pipe_format format, int samples);
st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw);
extern void
st_init_fbo_functions(struct dd_function_table *functions);

View File

@@ -63,20 +63,20 @@ st_create_framebuffer( const __GLcontextModes *visual,
/* XXX allocation should only happen in the unusual case
it's actually needed */
struct gl_renderbuffer *rb
= st_new_renderbuffer_fb(colorFormat, samples);
= st_new_renderbuffer_fb(colorFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_FRONT_LEFT, rb);
}
if (visual->doubleBufferMode) {
struct gl_renderbuffer *rb
= st_new_renderbuffer_fb(colorFormat, samples);
= st_new_renderbuffer_fb(colorFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_BACK_LEFT, rb);
}
if (depthFormat == stencilFormat && depthFormat != PIPE_FORMAT_NONE) {
/* combined depth/stencil buffer */
struct gl_renderbuffer *depthStencilRb
= st_new_renderbuffer_fb(depthFormat, samples);
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
/* note: bind RB to two attachment points */
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthStencilRb);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, depthStencilRb);
@@ -87,34 +87,35 @@ st_create_framebuffer( const __GLcontextModes *visual,
if (visual->depthBits == 32) {
/* 32-bit depth buffer */
struct gl_renderbuffer *depthRb
= st_new_renderbuffer_fb(depthFormat, samples);
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
}
else if (visual->depthBits == 24) {
/* 24-bit depth buffer, ignore stencil bits */
struct gl_renderbuffer *depthRb
= st_new_renderbuffer_fb(depthFormat, samples);
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
}
else if (visual->depthBits > 0) {
/* 16-bit depth buffer */
struct gl_renderbuffer *depthRb
= st_new_renderbuffer_fb(depthFormat, samples);
= st_new_renderbuffer_fb(depthFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_DEPTH, depthRb);
}
if (visual->stencilBits > 0) {
/* 8-bit stencil */
struct gl_renderbuffer *stencilRb
= st_new_renderbuffer_fb(stencilFormat, samples);
= st_new_renderbuffer_fb(stencilFormat, samples, FALSE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_STENCIL, stencilRb);
}
}
if (visual->accumRedBits > 0) {
/* 16-bit/channel accum */
/* TODO: query the pipe screen for accumulation buffer format support */
struct gl_renderbuffer *accumRb
= st_new_renderbuffer_fb(DEFAULT_ACCUM_PIPE_FORMAT, 0); /* XXX accum isn't multisampled right? */
= st_new_renderbuffer_fb(PIPE_FORMAT_R16G16B16A16_SNORM, 0, TRUE);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_ACCUM, accumRb);
}