From a73ae3d5eb8419feab5aea26573aa41b72f941eb Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Fri, 2 May 2008 16:46:31 +0100 Subject: [PATCH] gallium: Add texture usage flags, special-case allocation of display targets For many envirionments it's necessary to allocate display targets in a window-system friendly manner. Add facilities so that a driver can tell if a texture is likely to be used to generate a display surface and if use special allocation paths if necessary. Hook up softpipe to call into the winsys->surface_alloc_storage() routine in this case, though we probably want to change that interface slightly also. --- src/gallium/drivers/softpipe/sp_texture.c | 101 ++++++++++++------ src/gallium/drivers/softpipe/sp_texture.h | 2 +- src/gallium/include/pipe/p_state.h | 6 +- .../state_tracker/st_atom_pixeltransfer.c | 3 +- src/mesa/state_tracker/st_cb_bitmap.c | 6 +- src/mesa/state_tracker/st_cb_drawpixels.c | 6 +- src/mesa/state_tracker/st_cb_fbo.c | 23 ++-- src/mesa/state_tracker/st_cb_texture.c | 10 +- src/mesa/state_tracker/st_texture.c | 4 +- src/mesa/state_tracker/st_texture.h | 3 +- 10 files changed, 111 insertions(+), 53 deletions(-) diff --git a/src/gallium/drivers/softpipe/sp_texture.c b/src/gallium/drivers/softpipe/sp_texture.c index 2b31cd4f251..599ff2ac458 100644 --- a/src/gallium/drivers/softpipe/sp_texture.c +++ b/src/gallium/drivers/softpipe/sp_texture.c @@ -52,40 +52,87 @@ static unsigned minify( unsigned d ) } -static void -softpipe_texture_layout(struct softpipe_texture * spt) +/* Conventional allocation path for non-display textures: + */ +static boolean +softpipe_texture_layout(struct pipe_screen *screen, + struct softpipe_texture * spt) { + struct pipe_winsys *ws = screen->winsys; struct pipe_texture *pt = &spt->base; unsigned level; unsigned width = pt->width[0]; unsigned height = pt->height[0]; unsigned depth = pt->depth[0]; - spt->buffer_size = 0; + unsigned buffer_size = 0; for (level = 0; level <= pt->last_level; level++) { pt->width[level] = width; pt->height[level] = height; pt->depth[level] = depth; + spt->pitch[level] = width; - spt->level_offset[level] = spt->buffer_size; + spt->level_offset[level] = buffer_size; - spt->buffer_size += ((pt->compressed) ? MAX2(1, height/4) : height) * - ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * - width * pt->cpp; + buffer_size += (((pt->compressed) ? MAX2(1, height/4) : height) * + ((pt->target == PIPE_TEXTURE_CUBE) ? 6 : depth) * + width * pt->cpp); width = minify(width); height = minify(height); depth = minify(depth); } + + spt->buffer = ws->buffer_create(ws, 32, + PIPE_BUFFER_USAGE_PIXEL, + buffer_size); + + return spt->buffer != NULL; } + +/* Hack it up to use the old winsys->surface_alloc_storage() + * method for now: + */ +static boolean +softpipe_displaytarget_layout(struct pipe_screen *screen, + struct softpipe_texture * spt) +{ + struct pipe_winsys *ws = screen->winsys; + struct pipe_surface surf; + unsigned flags = (PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE | + PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE); + + + memset(&surf, 0, sizeof(surf)); + + ws->surface_alloc_storage( ws, + &surf, + spt->base.width[0], + spt->base.height[0], + spt->base.format, + flags); + + /* Now extract the goodies: + */ + spt->buffer = surf.buffer; + spt->pitch[0] = surf.pitch; + + return spt->buffer != NULL; +} + + + + + static struct pipe_texture * softpipe_texture_create(struct pipe_screen *screen, const struct pipe_texture *templat) { - struct pipe_winsys *ws = screen->winsys; struct softpipe_texture *spt = CALLOC_STRUCT(softpipe_texture); if (!spt) return NULL; @@ -94,19 +141,21 @@ softpipe_texture_create(struct pipe_screen *screen, spt->base.refcount = 1; spt->base.screen = screen; - softpipe_texture_layout(spt); - - spt->buffer = ws->buffer_create(ws, 32, - PIPE_BUFFER_USAGE_PIXEL, - spt->buffer_size); - if (!spt->buffer) { - FREE(spt); - return NULL; + if (spt->base.tex_usage & PIPE_TEXTURE_USAGE_DISPLAY_TARGET) { + if (!softpipe_displaytarget_layout(screen, spt)) + goto fail; } - + else { + if (!softpipe_texture_layout(screen, spt)) + goto fail; + } + assert(spt->base.refcount == 1); - return &spt->base; + + fail: + FREE(spt); + return NULL; } @@ -178,22 +227,6 @@ softpipe_get_tex_surface(struct pipe_screen *screen, assert(face == 0); assert(zslice == 0); } - - if (usage & (PIPE_BUFFER_USAGE_CPU_WRITE | - PIPE_BUFFER_USAGE_GPU_WRITE)) { - /* XXX if writing to the texture, invalidate the texcache entries!!! - * - * Actually, no. Flushing dependent contexts is still done - * explicitly and separately. Hardware drivers won't insert - * FLUSH commands into a command stream at this point, - * neither should softpipe try to flush caches. - * - * Those contexts could be living in separate threads & doing - * all sorts of unrelated stuff... Context<->texture - * dependency tracking needs to happen elsewhere. - */ - /* assert(0); */ - } } return ps; } diff --git a/src/gallium/drivers/softpipe/sp_texture.h b/src/gallium/drivers/softpipe/sp_texture.h index 2ba093320dc..779a9d8fc97 100644 --- a/src/gallium/drivers/softpipe/sp_texture.h +++ b/src/gallium/drivers/softpipe/sp_texture.h @@ -42,11 +42,11 @@ struct softpipe_texture struct pipe_texture base; unsigned long level_offset[PIPE_MAX_TEXTURE_LEVELS]; + unsigned long pitch[PIPE_MAX_TEXTURE_LEVELS]; /* The data is held here: */ struct pipe_buffer *buffer; - unsigned long buffer_size; }; diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h index 277ee4b3190..d7565dff960 100644 --- a/src/gallium/include/pipe/p_state.h +++ b/src/gallium/include/pipe/p_state.h @@ -284,6 +284,10 @@ struct pipe_surface }; +#define PIPE_TEXTURE_USAGE_RENDER_TARGET 0x1 +#define PIPE_TEXTURE_USAGE_DISPLAY_TARGET 0x2 /* ie a backbuffer */ +#define PIPE_TEXTURE_USAGE_SAMPLER 0x4 + /** * Texture object. */ @@ -300,7 +304,7 @@ struct pipe_texture unsigned last_level:8; /**< Index of last mipmap level present/defined */ unsigned compressed:1; - unsigned usage; + unsigned tex_usage; /* PIPE_TEXTURE_USAGE_* */ /* These are also refcounted: */ diff --git a/src/mesa/state_tracker/st_atom_pixeltransfer.c b/src/mesa/state_tracker/st_atom_pixeltransfer.c index 0c32d53c4ab..e500ac8684d 100644 --- a/src/mesa/state_tracker/st_atom_pixeltransfer.c +++ b/src/mesa/state_tracker/st_atom_pixeltransfer.c @@ -126,7 +126,8 @@ create_color_map_texture(GLcontext *ctx) /* create texture for color map/table */ pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, format, 0, - texSize, texSize, 1, 0); + texSize, texSize, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); return pt; } diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c index 873b765c2c2..f816e591042 100644 --- a/src/mesa/state_tracker/st_cb_bitmap.c +++ b/src/mesa/state_tracker/st_cb_bitmap.c @@ -321,7 +321,8 @@ make_bitmap_texture(GLcontext *ctx, GLsizei width, GLsizei height, * Create texture to hold bitmap pattern. */ pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, ctx->st->bitmap.tex_format, - 0, width, height, 1, 0); + 0, width, height, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) { _mesa_unmap_bitmap_pbo(ctx, unpack); return NULL; @@ -539,7 +540,8 @@ reset_cache(struct st_context *st) cache->texture = st_texture_create(st, PIPE_TEXTURE_2D, st->bitmap.tex_format, 0, BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, - 1, 0); + 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); /* Map the texture surface. * Subsequent glBitmap calls will write into the texture image. diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c index 9ae53c95f86..8c775ad8864 100644 --- a/src/mesa/state_tracker/st_cb_drawpixels.c +++ b/src/mesa/state_tracker/st_cb_drawpixels.c @@ -346,7 +346,8 @@ make_texture(struct st_context *st, return NULL; pt = st_texture_create(st, PIPE_TEXTURE_2D, pipeFormat, 0, width, height, - 1, 0); + 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) { _mesa_unmap_drawpix_pbo(ctx, unpack); return NULL; @@ -994,7 +995,8 @@ st_CopyPixels(GLcontext *ctx, GLint srcx, GLint srcy, } pt = st_texture_create(ctx->st, PIPE_TEXTURE_2D, texFormat, 0, - width, height, 1, 0); + width, height, 1, 0, + PIPE_TEXTURE_USAGE_SAMPLER); if (!pt) return; diff --git a/src/mesa/state_tracker/st_cb_fbo.c b/src/mesa/state_tracker/st_cb_fbo.c index b1747141710..21d61e21638 100644 --- a/src/mesa/state_tracker/st_cb_fbo.c +++ b/src/mesa/state_tracker/st_cb_fbo.c @@ -90,8 +90,8 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, { struct pipe_context *pipe = ctx->st->pipe; struct st_renderbuffer *strb = st_renderbuffer(rb); - struct pipe_texture template, *texture; + unsigned surface_usage; /* Free the old surface (and texture if we hold the last * reference): @@ -117,10 +117,15 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, template.height[0] = height; template.depth[0] = 1; template.last_level = 0; - template.usage = (PIPE_BUFFER_USAGE_CPU_WRITE | - PIPE_BUFFER_USAGE_CPU_READ | - PIPE_BUFFER_USAGE_GPU_WRITE | - PIPE_BUFFER_USAGE_GPU_READ); + template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET | + PIPE_TEXTURE_USAGE_RENDER_TARGET); + + /* Probably need dedicated flags for surface usage too: + */ + surface_usage = (PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE | + PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE); texture = pipe->screen->texture_create( pipe->screen, &template ); @@ -137,11 +142,13 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, * to tell the driver to go ahead and allocate the buffer, even * if HW doesn't support the format. */ - template.usage = (PIPE_BUFFER_USAGE_CPU_READ | - PIPE_BUFFER_USAGE_CPU_WRITE); + template.tex_usage = 0; + surface_usage = (PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE); texture = pipe->screen->texture_create( pipe->screen, &template ); + } if (!texture) @@ -150,7 +157,7 @@ st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, strb->surface = pipe->screen->get_tex_surface( pipe->screen, texture, 0, 0, 0, - template.usage ); + surface_usage ); pipe_texture_reference( &texture, NULL ); diff --git a/src/mesa/state_tracker/st_cb_texture.c b/src/mesa/state_tracker/st_cb_texture.c index 4cca3364c15..06caa06e776 100644 --- a/src/mesa/state_tracker/st_cb_texture.c +++ b/src/mesa/state_tracker/st_cb_texture.c @@ -333,7 +333,9 @@ guess_and_alloc_texture(struct st_context *st, width, height, depth, - comp_byte); + comp_byte, + ( PIPE_TEXTURE_USAGE_RENDER_TARGET | + PIPE_TEXTURE_USAGE_SAMPLER )); DBG("%s - success\n", __FUNCTION__); } @@ -1501,7 +1503,11 @@ st_finalize_texture(GLcontext *ctx, firstImage->base.Width2, firstImage->base.Height2, firstImage->base.Depth2, - comp_byte); + comp_byte, + + ( PIPE_TEXTURE_USAGE_RENDER_TARGET | + PIPE_TEXTURE_USAGE_SAMPLER )); + if (!stObj->pt) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); return GL_FALSE; diff --git a/src/mesa/state_tracker/st_texture.c b/src/mesa/state_tracker/st_texture.c index d6268fc80ca..2b3742d4e5b 100644 --- a/src/mesa/state_tracker/st_texture.c +++ b/src/mesa/state_tracker/st_texture.c @@ -75,7 +75,8 @@ st_texture_create(struct st_context *st, GLuint width0, GLuint height0, GLuint depth0, - GLuint compress_byte) + GLuint compress_byte, + GLuint usage ) { struct pipe_texture pt, *newtex; struct pipe_screen *screen = st->pipe->screen; @@ -98,6 +99,7 @@ st_texture_create(struct st_context *st, pt.depth[0] = depth0; pt.compressed = compress_byte ? 1 : 0; pt.cpp = pt.compressed ? compress_byte : st_sizeof_format(format); + pt.tex_usage = usage; newtex = screen->texture_create(screen, &pt); diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h index f6d5733e210..6a9f08ec6b7 100644 --- a/src/mesa/state_tracker/st_texture.h +++ b/src/mesa/state_tracker/st_texture.h @@ -105,7 +105,8 @@ st_texture_create(struct st_context *st, GLuint width0, GLuint height0, GLuint depth0, - GLuint compress_byte); + GLuint compress_byte, + GLuint tex_usage ); /* Check if an image fits into an existing texture object. -- 2.30.2