gallium: accum buffer fixes

If the driver can't create a PIPE_FORMAT_R16G16B16A16_SNORM surface, create
an accum surface using a shallower format and taller height.  Since only the
accum buffer code accesses the surface the actual format doesn't really
matter, just that there's enough memory.
This commit is contained in:
Brian Paul 2008-04-07 14:53:49 -06:00
parent 29b65a709c
commit 0dd596fbc7
4 changed files with 84 additions and 11 deletions

View file

@ -56,6 +56,51 @@
*/
/**
* 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_surface *acc_ps,
uint x, uint y, uint w, uint h, float *p)
{
const enum pipe_format f = acc_ps->format;
const int cpp = acc_ps->cpp;
acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
acc_ps->cpp = 8;
pipe_get_tile_rgba(pipe, acc_ps, x, y, w, h, p);
acc_ps->format = f;
acc_ps->cpp = cpp;
}
/**
* 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_surface *acc_ps,
uint x, uint y, uint w, uint h, const float *p)
{
enum pipe_format f = acc_ps->format;
const int cpp = acc_ps->cpp;
acc_ps->format = DEFAULT_ACCUM_PIPE_FORMAT;
acc_ps->cpp = 8;
pipe_put_tile_rgba(pipe, acc_ps, x, y, w, h, p);
acc_ps->format = f;
acc_ps->cpp = cpp;
}
void
st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
{
@ -80,7 +125,9 @@ st_clear_accum_buffer(GLcontext *ctx, struct gl_renderbuffer *rb)
accBuf[i*4+3] = a;
}
pipe_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
free(accBuf);
}
@ -95,13 +142,13 @@ accum_mad(struct pipe_context *pipe, GLfloat scale, GLfloat bias,
accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
pipe_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
for (i = 0; i < 4 * width * height; i++) {
accBuf[i] = accBuf[i] * scale + bias;
}
pipe_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
free(accBuf);
}
@ -120,13 +167,13 @@ accum_accum(struct pipe_context *pipe, GLfloat value,
accBuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
pipe_get_tile_rgba(pipe, color_ps, xpos, ypos, width, height, colorBuf);
pipe_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
for (i = 0; i < 4 * width * height; i++) {
accBuf[i] = accBuf[i] + colorBuf[i] * value;
}
pipe_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, accBuf);
free(colorBuf);
free(accBuf);
@ -150,7 +197,7 @@ accum_load(struct pipe_context *pipe, GLfloat value,
buf[i] = buf[i] * value;
}
pipe_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, buf);
acc_put_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, buf);
free(buf);
}
@ -169,7 +216,7 @@ accum_return(GLcontext *ctx, GLfloat value,
abuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));
pipe_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, abuf);
acc_get_tile_rgba(pipe, acc_ps, xpos, ypos, width, height, abuf);
if (!colormask[0] || !colormask[1] || !colormask[2] || !colormask[3]) {
cbuf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat));

View file

@ -127,14 +127,37 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
pipeFormat,
flags);
if (ret || !strb->surface->buffer) {
return GL_FALSE; /* out of memory, try s/w buffer? */
if (pipeFormat == DEFAULT_ACCUM_PIPE_FORMAT) {
/* Accum buffer. 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.
*/
int sz, mult;
enum pipe_format accum_format;
/* allocate a buffer of (typically) double height to get 64bpp */
accum_format = st_choose_renderbuffer_format(pipe, GL_RGBA);
sz = pf_get_size(accum_format);
mult = pf_get_size(DEFAULT_ACCUM_PIPE_FORMAT) / sz;
ret = pipe->winsys->surface_alloc_storage(pipe->winsys,
strb->surface,
width, height * mult,
accum_format, flags);
if (ret)
return GL_FALSE; /* we've _really_ failed */
}
else {
return GL_FALSE; /* out of memory, try s/w buffer? */
}
}
ASSERT(strb->surface->buffer);
ASSERT(strb->surface->format);
ASSERT(strb->surface->cpp);
ASSERT(strb->surface->width == width);
ASSERT(strb->surface->height == height);
/*ASSERT(strb->surface->height == height);*/
ASSERT(strb->surface->pitch);
strb->Base.Width = width;
@ -252,7 +275,7 @@ st_new_renderbuffer_fb(enum pipe_format format)
strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
strb->Base._BaseFormat = GL_STENCIL_INDEX;
break;
case PIPE_FORMAT_R16G16B16A16_SNORM:
case DEFAULT_ACCUM_PIPE_FORMAT: /*PIPE_FORMAT_R16G16B16A16_SNORM*/
strb->Base.InternalFormat = GL_RGBA16;
strb->Base._BaseFormat = GL_RGBA;
break;

View file

@ -30,6 +30,9 @@
#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

View file

@ -107,7 +107,7 @@ st_create_framebuffer( const __GLcontextModes *visual,
if (visual->accumRedBits > 0) {
/* 16-bit/channel accum */
struct gl_renderbuffer *accumRb
= st_new_renderbuffer_fb(PIPE_FORMAT_R16G16B16A16_SNORM);
= st_new_renderbuffer_fb(DEFAULT_ACCUM_PIPE_FORMAT);
_mesa_add_renderbuffer(&stfb->Base, BUFFER_ACCUM, accumRb);
}