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.tags/mesa_20090313
| @@ -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; | |||
| } | |||
| @@ -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; | |||
| }; | |||
| @@ -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: | |||
| */ | |||
| @@ -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; | |||
| } | |||
| @@ -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. | |||
| @@ -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; | |||
| @@ -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 ); | |||
| @@ -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; | |||
| @@ -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); | |||
| @@ -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. | |||