static struct pipe_resource * softpipe_resource_from_handle(struct pipe_screen *screen, const struct pipe_resource *templat, struct winsys_handle *whandle) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; struct softpipe_resource *spr = CALLOC_STRUCT(softpipe_resource); if (!spr) return NULL; spr->base = *templat; pipe_reference_init(&spr->base.reference, 1); spr->base.screen = screen; spr->pot = (util_is_power_of_two(templat->width0) && util_is_power_of_two(templat->height0) && util_is_power_of_two(templat->depth0)); spr->dt = winsys->displaytarget_from_handle(winsys, templat, whandle, &spr->stride[0]); if (!spr->dt) goto fail; return &spr->base; fail: FREE(spr); return NULL; }
static int softpipe_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe_shader_cap param) { struct softpipe_screen *sp_screen = softpipe_screen(screen); switch(shader) { case PIPE_SHADER_FRAGMENT: return tgsi_exec_get_shader_param(param); case PIPE_SHADER_VERTEX: case PIPE_SHADER_GEOMETRY: switch (param) { case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: if (sp_screen->use_llvm) /* Softpipe doesn't yet know how to tell draw/llvm about textures */ return 0; else return PIPE_MAX_SAMPLERS; default: if (sp_screen->use_llvm) return draw_get_shader_param(shader, param); else return draw_get_shader_param_no_llvm(shader, param); } default: return 0; } }
static void gdi_present(struct pipe_screen *screen, struct pipe_resource *res, HDC hDC) { /* This will fail if any interposing layer (trace, debug, etc) has * been introduced between the state-trackers and the pipe driver. * * Ideally this would get replaced with a call to * pipe_screen::flush_frontbuffer(). * * Failing that, it may be necessary for intervening layers to wrap * other structs such as this stw_winsys as well... */ struct sw_winsys *winsys = NULL; struct sw_displaytarget *dt = NULL; #ifdef HAVE_LLVMPIPE if (use_llvmpipe) { winsys = llvmpipe_screen(screen)->winsys; dt = llvmpipe_resource(res)->dt; gdi_sw_display(winsys, dt, hDC); return; } #endif winsys = softpipe_screen(screen)->winsys, dt = softpipe_resource(res)->dt, gdi_sw_display(winsys, dt, hDC); }
static int softpipe_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe_shader_cap param) { #ifdef HAVE_LLVM struct softpipe_screen *sp_screen = softpipe_screen(screen); #endif switch(shader) { case PIPE_SHADER_FRAGMENT: return tgsi_exec_get_shader_param(param); case PIPE_SHADER_VERTEX: case PIPE_SHADER_GEOMETRY: switch (param) { case PIPE_SHADER_CAP_MAX_TEXTURE_SAMPLERS: #ifdef HAVE_LLVM if (sp_screen->use_llvm) /* Softpipe doesn't yet know how to tell draw/llvm about textures */ return 0; #endif return PIPE_MAX_VERTEX_SAMPLERS; case PIPE_SHADER_CAP_INTEGERS: #ifdef HAVE_LLVM /* gallivm doesn't support integers yet */ if (sp_screen->use_llvm) return 0; #endif /* fallthrough */ default: return draw_get_shader_param(shader, param); } default: return 0; } }
static void * softpipe_surface_map( struct pipe_screen *screen, struct pipe_surface *surface, unsigned flags ) { ubyte *map; if (flags & ~surface->usage) { assert(0); return NULL; } map = pipe_buffer_map( screen, surface->buffer, flags ); if (map == NULL) return NULL; /* May want to different things here depending on read/write nature * of the map: */ if (surface->texture && (flags & PIPE_BUFFER_USAGE_CPU_WRITE)) { /* Do something to notify sharing contexts of a texture change. * In softpipe, that would mean flushing the texture cache. */ softpipe_screen(screen)->timestamp++; } return map + surface->offset; }
/* Hopefully this will remain quite simple, otherwise need to pull in * something like the state tracker mechanism. */ void softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim) { struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen); /* Check for updated textures. */ if (softpipe->tex_timestamp != sp_screen->timestamp) { softpipe->tex_timestamp = sp_screen->timestamp; softpipe->dirty |= SP_NEW_TEXTURE; } #if DO_PSTIPPLE_IN_HELPER_MODULE if (softpipe->dirty & SP_NEW_STIPPLE) /* before updating samplers! */ update_polygon_stipple_pattern(softpipe); #endif if (softpipe->dirty & (SP_NEW_RASTERIZER | SP_NEW_FS)) update_fragment_shader(softpipe, prim); #if DO_PSTIPPLE_IN_HELPER_MODULE if (softpipe->dirty & (SP_NEW_RASTERIZER | SP_NEW_STIPPLE | SP_NEW_FS)) update_polygon_stipple_enable(softpipe, prim); #endif /* TODO: this looks suboptimal */ if (softpipe->dirty & (SP_NEW_SAMPLER | SP_NEW_TEXTURE | SP_NEW_FS | SP_NEW_VS)) update_tgsi_samplers( softpipe ); if (softpipe->dirty & (SP_NEW_RASTERIZER | SP_NEW_FS | SP_NEW_VS)) invalidate_vertex_layout( softpipe ); if (softpipe->dirty & (SP_NEW_SCISSOR | SP_NEW_RASTERIZER | SP_NEW_FRAMEBUFFER)) compute_cliprect(softpipe); if (softpipe->dirty & (SP_NEW_BLEND | SP_NEW_DEPTH_STENCIL_ALPHA | SP_NEW_FRAMEBUFFER | SP_NEW_STIPPLE | SP_NEW_FS)) sp_build_quad_pipeline(softpipe); softpipe->dirty = 0; }
static void softpipe_destroy_screen( struct pipe_screen *screen ) { struct softpipe_screen *sp_screen = softpipe_screen(screen); struct sw_winsys *winsys = sp_screen->winsys; if(winsys->destroy) winsys->destroy(winsys); FREE(screen); }
/* This is often overriden by the co-state tracker. */ static void softpipe_flush_frontbuffer(struct pipe_screen *_screen, struct pipe_resource *resource, unsigned level, unsigned layer, void *context_private) { struct softpipe_screen *screen = softpipe_screen(_screen); struct sw_winsys *winsys = screen->winsys; struct softpipe_resource *texture = softpipe_resource(resource); assert(texture->dt); if (texture->dt) winsys->displaytarget_display(winsys, texture->dt, context_private); }
static boolean softpipe_resource_get_handle(struct pipe_screen *screen, struct pipe_resource *pt, struct winsys_handle *whandle) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; struct softpipe_resource *spr = softpipe_resource(pt); assert(spr->dt); if (!spr->dt) return FALSE; return winsys->displaytarget_get_handle(winsys, spr->dt, whandle); }
/** * Texture layout for simple color buffers. */ static boolean softpipe_displaytarget_layout(struct pipe_screen *screen, struct softpipe_resource *spr) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; /* Round up the surface size to a multiple of the tile size? */ spr->dt = winsys->displaytarget_create(winsys, spr->base.bind, spr->base.format, spr->base.width0, spr->base.height0, 16, &spr->stride[0] ); return spr->dt != NULL; }
static int softpipe_get_shader_param(struct pipe_screen *screen, unsigned shader, enum pipe_shader_cap param) { struct softpipe_screen *sp_screen = softpipe_screen(screen); switch(shader) { case PIPE_SHADER_FRAGMENT: return tgsi_exec_get_shader_param(param); case PIPE_SHADER_VERTEX: case PIPE_SHADER_GEOMETRY: if (sp_screen->use_llvm) return draw_get_shader_param(shader, param); else return draw_get_shader_param_no_llvm(shader, param); default: return 0; } }
static void gdi_softpipe_present(struct pipe_screen *screen, struct pipe_surface *surface, HDC hDC) { /* This will fail if any interposing layer (trace, debug, etc) has * been introduced between the state-trackers and softpipe. * * Ideally this would get replaced with a call to * pipe_screen::flush_frontbuffer(). * * Failing that, it may be necessary for intervening layers to wrap * other structs such as this stw_winsys as well... */ gdi_sw_display(softpipe_screen(screen)->winsys, softpipe_resource(surface->texture)->dt, hDC); }
static void softpipe_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt) { struct softpipe_screen *screen = softpipe_screen(pscreen); struct softpipe_resource *spr = softpipe_resource(pt); if (spr->dt) { /* display target */ struct sw_winsys *winsys = screen->winsys; winsys->displaytarget_destroy(winsys, spr->dt); } else if (!spr->userBuffer) { /* regular texture */ align_free(spr->data); } FREE(spr); }
/** * Unmap memory mapping for given pipe_transfer object. */ static void softpipe_transfer_unmap(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct softpipe_resource *spr; assert(transfer->resource); spr = softpipe_resource(transfer->resource); if (spr->dt) { /* display target */ struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; winsys->displaytarget_unmap(winsys, spr->dt); } if (transfer->usage & PIPE_TRANSFER_WRITE) { /* Mark the texture as dirty to expire the tile caches. */ spr->timestamp++; } }
static void * softpipe_transfer_map( struct pipe_screen *screen, struct pipe_transfer *transfer ) { ubyte *map, *xfer_map; struct softpipe_texture *spt; unsigned flags = 0; assert(transfer->texture); spt = softpipe_texture(transfer->texture); if (transfer->usage != PIPE_TRANSFER_READ) { flags |= PIPE_BUFFER_USAGE_CPU_WRITE; } if (transfer->usage != PIPE_TRANSFER_WRITE) { flags |= PIPE_BUFFER_USAGE_CPU_READ; } map = pipe_buffer_map(screen, spt->buffer, flags); if (map == NULL) return NULL; /* May want to different things here depending on read/write nature * of the map: */ if (transfer->texture && transfer->usage != PIPE_TRANSFER_READ) { /* Do something to notify sharing contexts of a texture change. * In softpipe, that would mean flushing the texture cache. */ softpipe_screen(screen)->timestamp++; } xfer_map = map + softpipe_transfer(transfer)->offset + transfer->y / transfer->block.height * transfer->stride + transfer->x / transfer->block.width * transfer->block.size; /*printf("map = %p xfer map = %p\n", map, xfer_map);*/ return xfer_map; }
/** * Create memory mapping for given pipe_transfer object. */ static void * softpipe_transfer_map(struct pipe_context *pipe, struct pipe_transfer *transfer) { struct softpipe_transfer *spt = softpipe_transfer(transfer); struct softpipe_resource *spr = softpipe_resource(transfer->resource); struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; uint8_t *map; /* resources backed by display target treated specially: */ if (spr->dt) { map = winsys->displaytarget_map(winsys, spr->dt, transfer->usage); } else { map = spr->data; } if (map == NULL) return NULL; else return map + spt->offset; }
struct pipe_context * softpipe_create_context( struct pipe_screen *screen, void *priv ) { struct softpipe_screen *sp_screen = softpipe_screen(screen); struct softpipe_context *softpipe = CALLOC_STRUCT(softpipe_context); uint i, sh; util_init_math(); softpipe->dump_fs = debug_get_bool_option( "SOFTPIPE_DUMP_FS", FALSE ); softpipe->dump_gs = debug_get_bool_option( "SOFTPIPE_DUMP_GS", FALSE ); softpipe->pipe.screen = screen; softpipe->pipe.destroy = softpipe_destroy; softpipe->pipe.priv = priv; /* state setters */ softpipe_init_blend_funcs(&softpipe->pipe); softpipe_init_clip_funcs(&softpipe->pipe); softpipe_init_query_funcs( softpipe ); softpipe_init_rasterizer_funcs(&softpipe->pipe); softpipe_init_sampler_funcs(&softpipe->pipe); softpipe_init_shader_funcs(&softpipe->pipe); softpipe_init_streamout_funcs(&softpipe->pipe); softpipe_init_texture_funcs( &softpipe->pipe ); softpipe_init_vertex_funcs(&softpipe->pipe); softpipe->pipe.set_framebuffer_state = softpipe_set_framebuffer_state; softpipe->pipe.draw_vbo = softpipe_draw_vbo; softpipe->pipe.clear = softpipe_clear; softpipe->pipe.flush = softpipe_flush_wrapped; softpipe->pipe.render_condition = softpipe_render_condition; softpipe->pipe.create_video_decoder = vl_create_decoder; softpipe->pipe.create_video_buffer = vl_video_buffer_create; /* * Alloc caches for accessing drawing surfaces and textures. * Must be before quad stage setup! */ for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) softpipe->cbuf_cache[i] = sp_create_tile_cache( &softpipe->pipe ); softpipe->zsbuf_cache = sp_create_tile_cache( &softpipe->pipe ); /* Allocate texture caches */ for (sh = 0; sh < Elements(softpipe->tex_cache); sh++) { for (i = 0; i < Elements(softpipe->tex_cache[0]); i++) { softpipe->tex_cache[sh][i] = sp_create_tex_tile_cache(&softpipe->pipe); if (!softpipe->tex_cache[sh][i]) goto fail; } } softpipe->fs_machine = tgsi_exec_machine_create(); /* setup quad rendering stages */ softpipe->quad.shade = sp_quad_shade_stage(softpipe); softpipe->quad.depth_test = sp_quad_depth_test_stage(softpipe); softpipe->quad.blend = sp_quad_blend_stage(softpipe); softpipe->quad.pstipple = sp_quad_polygon_stipple_stage(softpipe); /* * Create drawing context and plug our rendering stage into it. */ if (sp_screen->use_llvm) softpipe->draw = draw_create(&softpipe->pipe); else softpipe->draw = draw_create_no_llvm(&softpipe->pipe); if (!softpipe->draw) goto fail; draw_texture_samplers(softpipe->draw, PIPE_SHADER_VERTEX, PIPE_MAX_SAMPLERS, (struct tgsi_sampler **) softpipe->tgsi.samplers_list[PIPE_SHADER_VERTEX]); draw_texture_samplers(softpipe->draw, PIPE_SHADER_GEOMETRY, PIPE_MAX_SAMPLERS, (struct tgsi_sampler **) softpipe->tgsi.samplers_list[PIPE_SHADER_GEOMETRY]); if (debug_get_bool_option( "SOFTPIPE_NO_RAST", FALSE )) softpipe->no_rast = TRUE; softpipe->vbuf_backend = sp_create_vbuf_backend(softpipe); if (!softpipe->vbuf_backend) goto fail; softpipe->vbuf = draw_vbuf_stage(softpipe->draw, softpipe->vbuf_backend); if (!softpipe->vbuf) goto fail; draw_set_rasterize_stage(softpipe->draw, softpipe->vbuf); draw_set_render(softpipe->draw, softpipe->vbuf_backend); /* plug in AA line/point stages */ draw_install_aaline_stage(softpipe->draw, &softpipe->pipe); draw_install_aapoint_stage(softpipe->draw, &softpipe->pipe); /* Do polygon stipple w/ texture map + frag prog? */ #if DO_PSTIPPLE_IN_DRAW_MODULE draw_install_pstipple_stage(softpipe->draw, &softpipe->pipe); #endif draw_wide_point_sprites(softpipe->draw, TRUE); sp_init_surface_functions(softpipe); #if DO_PSTIPPLE_IN_HELPER_MODULE /* create the polgon stipple sampler */ softpipe->pstipple.sampler = util_pstipple_create_sampler(&softpipe->pipe); #endif return &softpipe->pipe; fail: softpipe_destroy(&softpipe->pipe); return NULL; }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean softpipe_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; const struct util_format_description *format_desc; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); format_desc = util_format_description(format); if (!format_desc) return FALSE; if (sample_count > 1) return FALSE; if (bind & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* * Although possible, it is unnatural to render into compressed or YUV * surfaces. So disable these here to avoid going into weird paths * inside the state trackers. */ if (format_desc->block.width != 1 || format_desc->block.height != 1) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; } if (format_desc->layout == UTIL_FORMAT_LAYOUT_BPTC || format_desc->layout == UTIL_FORMAT_LAYOUT_ASTC) { /* Software decoding is not hooked up. */ return FALSE; } if ((bind & (PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW)) && ((bind & PIPE_BIND_DISPLAY_TARGET) == 0) && target != PIPE_BUFFER) { const struct util_format_description *desc = util_format_description(format); if (desc->nr_channels == 3 && desc->is_array) { /* Don't support any 3-component formats for rendering/texturing * since we don't support the corresponding 8-bit 3 channel UNORM * formats. This allows us to support GL_ARB_copy_image between * GL_RGB8 and GL_RGB8UI, for example. Otherwise, we may be asked to * do a resource copy between PIPE_FORMAT_R8G8B8_UINT and * PIPE_FORMAT_R8G8B8X8_UNORM, for example, which will not work * (different bpp). */ return FALSE; } } if (format_desc->layout == UTIL_FORMAT_LAYOUT_ETC && format != PIPE_FORMAT_ETC1_RGB8) return FALSE; /* * All other operations (sampling, transfer, etc). */ /* * Everything else should be supported by u_format. */ return TRUE; }
/** * Query format support for creating a texture, drawing surface, etc. * \param format the format to test * \param type one of PIPE_TEXTURE, PIPE_SURFACE */ static boolean softpipe_is_format_supported( struct pipe_screen *screen, enum pipe_format format, enum pipe_texture_target target, unsigned sample_count, unsigned bind) { struct sw_winsys *winsys = softpipe_screen(screen)->winsys; const struct util_format_description *format_desc; assert(target == PIPE_BUFFER || target == PIPE_TEXTURE_1D || target == PIPE_TEXTURE_1D_ARRAY || target == PIPE_TEXTURE_2D || target == PIPE_TEXTURE_2D_ARRAY || target == PIPE_TEXTURE_RECT || target == PIPE_TEXTURE_3D || target == PIPE_TEXTURE_CUBE || target == PIPE_TEXTURE_CUBE_ARRAY); format_desc = util_format_description(format); if (!format_desc) return FALSE; if (sample_count > 1) return FALSE; if (bind & (PIPE_BIND_DISPLAY_TARGET | PIPE_BIND_SCANOUT | PIPE_BIND_SHARED)) { if(!winsys->is_displaytarget_format_supported(winsys, bind, format)) return FALSE; } if (bind & PIPE_BIND_RENDER_TARGET) { if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_ZS) return FALSE; /* * Although possible, it is unnatural to render into compressed or YUV * surfaces. So disable these here to avoid going into weird paths * inside the state trackers. */ if (format_desc->block.width != 1 || format_desc->block.height != 1) return FALSE; } if (bind & PIPE_BIND_DEPTH_STENCIL) { if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_ZS) return FALSE; } /* * All other operations (sampling, transfer, etc). */ if (format_desc->layout == UTIL_FORMAT_LAYOUT_S3TC) { return util_format_s3tc_enabled; } /* * Everything else should be supported by u_format. */ return TRUE; }
static void prepare_shader_sampling( struct softpipe_context *sp, unsigned num, struct pipe_sampler_view **views, unsigned shader_type, struct pipe_resource *mapped_tex[PIPE_MAX_SHADER_SAMPLER_VIEWS]) { unsigned i; uint32_t row_stride[PIPE_MAX_TEXTURE_LEVELS]; uint32_t img_stride[PIPE_MAX_TEXTURE_LEVELS]; uint32_t mip_offsets[PIPE_MAX_TEXTURE_LEVELS]; const void *addr; assert(num <= PIPE_MAX_SHADER_SAMPLER_VIEWS); if (!num) return; for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) { struct pipe_sampler_view *view = i < num ? views[i] : NULL; if (view) { struct pipe_resource *tex = view->texture; struct softpipe_resource *sp_tex = softpipe_resource(tex); unsigned width0 = tex->width0; unsigned num_layers = tex->depth0; unsigned first_level = 0; unsigned last_level = 0; /* We're referencing the texture's internal data, so save a * reference to it. */ pipe_resource_reference(&mapped_tex[i], tex); if (!sp_tex->dt) { /* regular texture - setup array of mipmap level offsets */ MAYBE_UNUSED struct pipe_resource *res = view->texture; int j; if (view->target != PIPE_BUFFER) { first_level = view->u.tex.first_level; last_level = view->u.tex.last_level; assert(first_level <= last_level); assert(last_level <= res->last_level); addr = sp_tex->data; for (j = first_level; j <= last_level; j++) { mip_offsets[j] = sp_tex->level_offset[j]; row_stride[j] = sp_tex->stride[j]; img_stride[j] = sp_tex->img_stride[j]; } if (tex->target == PIPE_TEXTURE_1D_ARRAY || tex->target == PIPE_TEXTURE_2D_ARRAY || tex->target == PIPE_TEXTURE_CUBE || tex->target == PIPE_TEXTURE_CUBE_ARRAY) { num_layers = view->u.tex.last_layer - view->u.tex.first_layer + 1; for (j = first_level; j <= last_level; j++) { mip_offsets[j] += view->u.tex.first_layer * sp_tex->img_stride[j]; } if (view->target == PIPE_TEXTURE_CUBE || view->target == PIPE_TEXTURE_CUBE_ARRAY) { assert(num_layers % 6 == 0); } assert(view->u.tex.first_layer <= view->u.tex.last_layer); assert(view->u.tex.last_layer < res->array_size); } } else { unsigned view_blocksize = util_format_get_blocksize(view->format); addr = sp_tex->data; /* probably don't really need to fill that out */ mip_offsets[0] = 0; row_stride[0] = 0; img_stride[0] = 0; /* everything specified in number of elements here. */ width0 = view->u.buf.last_element - view->u.buf.first_element + 1; addr = (uint8_t *)addr + view->u.buf.first_element * view_blocksize; assert(view->u.buf.first_element <= view->u.buf.last_element); assert(view->u.buf.last_element * view_blocksize < res->width0); } } else { /* display target texture/surface */ /* * XXX: Where should this be unmapped? */ struct softpipe_screen *screen = softpipe_screen(tex->screen); struct sw_winsys *winsys = screen->winsys; addr = winsys->displaytarget_map(winsys, sp_tex->dt, PIPE_TRANSFER_READ); row_stride[0] = sp_tex->stride[0]; img_stride[0] = sp_tex->img_stride[0]; mip_offsets[0] = 0; assert(addr); } draw_set_mapped_texture(sp->draw, shader_type, i, width0, tex->height0, num_layers, first_level, last_level, addr, row_stride, img_stride, mip_offsets); } } }
/** * Geta pipe_transfer object which is used for moving data in/out of * a resource object. * \param pipe rendering context * \param resource the resource to transfer in/out of * \param level which mipmap level * \param usage bitmask of PIPE_TRANSFER_x flags * \param box the 1D/2D/3D region of interest */ static void * softpipe_transfer_map(struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box, struct pipe_transfer **transfer) { struct sw_winsys *winsys = softpipe_screen(pipe->screen)->winsys; struct softpipe_resource *spr = softpipe_resource(resource); struct softpipe_transfer *spt; struct pipe_transfer *pt; enum pipe_format format = resource->format; uint8_t *map; assert(resource); assert(level <= resource->last_level); /* make sure the requested region is in the image bounds */ assert(box->x + box->width <= (int) u_minify(resource->width0, level)); if (resource->target == PIPE_TEXTURE_1D_ARRAY) { assert(box->y + box->height <= (int) resource->array_size); } else { assert(box->y + box->height <= (int) u_minify(resource->height0, level)); if (resource->target == PIPE_TEXTURE_2D_ARRAY) { assert(box->z + box->depth <= (int) resource->array_size); } else if (resource->target == PIPE_TEXTURE_CUBE) { assert(box->z < 6); } else if (resource->target == PIPE_TEXTURE_CUBE_ARRAY) { assert(box->z <= (int) resource->array_size); } else { assert(box->z + box->depth <= (int) u_minify(resource->depth0, level)); } } /* * Transfers, like other pipe operations, must happen in order, so flush the * context if necessary. */ if (!(usage & PIPE_TRANSFER_UNSYNCHRONIZED)) { boolean read_only = !(usage & PIPE_TRANSFER_WRITE); boolean do_not_block = !!(usage & PIPE_TRANSFER_DONTBLOCK); if (!softpipe_flush_resource(pipe, resource, level, box->depth > 1 ? -1 : box->z, 0, /* flush_flags */ read_only, TRUE, /* cpu_access */ do_not_block)) { /* * It would have blocked, but state tracker requested no to. */ assert(do_not_block); return NULL; } } spt = CALLOC_STRUCT(softpipe_transfer); if (!spt) return NULL; pt = &spt->base; pipe_resource_reference(&pt->resource, resource); pt->level = level; pt->usage = usage; pt->box = *box; pt->stride = spr->stride[level]; pt->layer_stride = spr->img_stride[level]; spt->offset = softpipe_get_tex_image_offset(spr, level, box->z); spt->offset += box->y / util_format_get_blockheight(format) * spt->base.stride + box->x / util_format_get_blockwidth(format) * util_format_get_blocksize(format); /* resources backed by display target treated specially: */ if (spr->dt) { map = winsys->displaytarget_map(winsys, spr->dt, usage); } else { map = spr->data; } if (!map) { pipe_resource_reference(&pt->resource, NULL); FREE(spt); return NULL; } *transfer = pt; return map + spt->offset; }