static void upload_unmap_internal(struct u_upload_mgr *upload, boolean destroying) { if (!upload->transfer) return; if (upload->map_flags & PIPE_TRANSFER_FLUSH_EXPLICIT) { struct pipe_box *box = &upload->transfer->box; unsigned flush_offset = box->x + upload->flushed_size; if (upload->offset > flush_offset) { pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer, flush_offset, upload->offset - flush_offset); upload->flushed_size = upload->offset; } } if (destroying || !upload->map_persistent) { pipe_transfer_unmap(upload->pipe, upload->transfer); upload->transfer = NULL; upload->map = NULL; upload->flushed_size = 0; } }
static void set_random_pixels(struct pipe_context *ctx, struct pipe_resource *tex, struct cpu_texture *cpu) { struct pipe_transfer *t; uint8_t *map; int x,y,z; map = pipe_transfer_map_3d(ctx, tex, 0, PIPE_TRANSFER_WRITE, 0, 0, 0, tex->width0, tex->height0, tex->array_size, &t); assert(map); for (z = 0; z < tex->array_size; z++) { for (y = 0; y < tex->height0; y++) { uint64_t *ptr = (uint64_t*) (map + t->layer_stride*z + t->stride*y); uint64_t *ptr_cpu = (uint64_t*) (cpu->ptr + cpu->layer_stride*z + cpu->stride*y); unsigned size = cpu->stride / RAND_NUM_SIZE; assert(t->stride % RAND_NUM_SIZE == 0); assert(cpu->stride % RAND_NUM_SIZE == 0); for (x = 0; x < size; x++) { *ptr++ = *ptr_cpu++ = rand_xorshift128plus(seed_xorshift128plus); } } } pipe_transfer_unmap(ctx, t); }
static bool compare_textures(struct pipe_context *ctx, struct pipe_resource *tex, struct cpu_texture *cpu, int bpp) { struct pipe_transfer *t; uint8_t *map; int y,z; bool pass = true; map = pipe_transfer_map_3d(ctx, tex, 0, PIPE_TRANSFER_READ, 0, 0, 0, tex->width0, tex->height0, tex->array_size, &t); assert(map); for (z = 0; z < tex->array_size; z++) { for (y = 0; y < tex->height0; y++) { uint8_t *ptr = map + t->layer_stride*z + t->stride*y; uint8_t *cpu_ptr = cpu->ptr + cpu->layer_stride*z + cpu->stride*y; if (memcmp(ptr, cpu_ptr, tex->width0 * bpp)) { pass = false; goto done; } } } done: pipe_transfer_unmap(ctx, t); return pass; }
void u_default_buffer_subdata(struct pipe_context *pipe, struct pipe_resource *resource, unsigned usage, unsigned offset, unsigned size, const void *data) { struct pipe_transfer *transfer = NULL; struct pipe_box box; uint8_t *map = NULL; assert(!(usage & PIPE_TRANSFER_READ)); /* the write flag is implicit by the nature of buffer_subdata */ usage |= PIPE_TRANSFER_WRITE; /* buffer_subdata implicitly discards the rewritten buffer range */ if (offset == 0 && size == resource->width0) { usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; } else { usage |= PIPE_TRANSFER_DISCARD_RANGE; } u_box_1d(offset, size, &box); map = pipe->transfer_map(pipe, resource, 0, usage, &box, &transfer); if (!map) return; memcpy(map, data, size); pipe_transfer_unmap(pipe, transfer); }
/** Per-context tear-down */ void st_destroy_bitmap(struct st_context *st) { struct pipe_context *pipe = st->pipe; struct bitmap_cache *cache = st->bitmap.cache; if (st->bitmap.vs) { cso_delete_vertex_shader(st->cso_context, st->bitmap.vs); st->bitmap.vs = NULL; } if (st->bitmap.vbuf) { pipe_resource_reference(&st->bitmap.vbuf, NULL); st->bitmap.vbuf = NULL; } if (cache) { if (cache->trans) { pipe_transfer_unmap(pipe, cache->trans); pipe->transfer_destroy(pipe, cache->trans); } pipe_resource_reference(&st->bitmap.cache->texture, NULL); free(st->bitmap.cache); st->bitmap.cache = NULL; } }
/* One-shot transfer operation with data supplied in a user * pointer. XXX: strides?? */ void u_default_transfer_inline_write( struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box, const void *data, unsigned stride, unsigned layer_stride) { struct pipe_transfer *transfer = NULL; uint8_t *map = NULL; assert(!(usage & PIPE_TRANSFER_READ)); /* the write flag is implicit by the nature of transfer_inline_write */ usage |= PIPE_TRANSFER_WRITE; /* transfer_inline_write implicitly discards the rewritten buffer range */ if (box->x == 0 && box->width == resource->width0) { usage |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE; } else { usage |= PIPE_TRANSFER_DISCARD_RANGE; } map = pipe->transfer_map(pipe, resource, level, usage, box, &transfer); if (map == NULL) return; if (resource->target == PIPE_BUFFER) { assert(box->height == 1); assert(box->depth == 1); memcpy(map, data, box->width); } else { const uint8_t *src_data = data; unsigned i; for (i = 0; i < box->depth; i++) { util_copy_rect(map, resource->format, transfer->stride, /* bytes */ 0, 0, box->width, box->height, src_data, stride, /* bytes */ 0, 0); map += transfer->layer_stride; src_data += layer_stride; } } pipe_transfer_unmap(pipe, transfer); }
void st_texture_image_unmap(struct st_context *st, struct st_texture_image *stImage) { struct pipe_context *pipe = st->pipe; DBG("%s\n", __FUNCTION__); pipe_transfer_unmap(pipe, stImage->transfer); stImage->transfer = NULL; }
/** * If there's anything in the bitmap cache, draw/flush it now. */ void st_flush_bitmap_cache(struct st_context *st) { if (!st->bitmap.cache->empty) { struct bitmap_cache *cache = st->bitmap.cache; if (st->ctx->DrawBuffer) { struct pipe_context *pipe = st->pipe; struct pipe_sampler_view *sv; assert(cache->xmin <= cache->xmax); /* printf("flush size %d x %d at %d, %d\n", cache->xmax - cache->xmin, cache->ymax - cache->ymin, cache->xpos, cache->ypos); */ /* The texture transfer has been mapped until now. * So unmap and release the texture transfer before drawing. */ if (cache->trans) { if (0) print_cache(cache); pipe_transfer_unmap(pipe, cache->trans); cache->buffer = NULL; pipe->transfer_destroy(pipe, cache->trans); cache->trans = NULL; } sv = st_create_texture_sampler_view(st->pipe, cache->texture); if (sv) { draw_bitmap_quad(st->ctx, cache->xpos, cache->ypos, cache->zpos, BITMAP_CACHE_WIDTH, BITMAP_CACHE_HEIGHT, sv, cache->color); pipe_sampler_view_reference(&sv, NULL); } } /* release/free the texture */ pipe_resource_reference(&cache->texture, NULL); reset_cache(st); } }
/** * Probe and test if the rectangle contains the expected color. * * If "num_expected_colors" > 1, at least one expected color must match * the probed color. "expected" should be an array of 4*num_expected_colors * floats. */ static bool util_probe_rect_rgba_multi(struct pipe_context *ctx, struct pipe_resource *tex, unsigned offx, unsigned offy, unsigned w, unsigned h, const float *expected, unsigned num_expected_colors) { struct pipe_transfer *transfer; void *map; float *pixels = malloc(w * h * 4 * sizeof(float)); int x,y,e,c; bool pass = true; map = pipe_transfer_map(ctx, tex, 0, 0, PIPE_TRANSFER_READ, offx, offy, w, h, &transfer); pipe_get_tile_rgba(transfer, map, 0, 0, w, h, pixels); pipe_transfer_unmap(ctx, transfer); for (e = 0; e < num_expected_colors; e++) { for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { float *probe = &pixels[(y*w + x)*4]; for (c = 0; c < 4; c++) { if (fabs(probe[c] - expected[e*4+c]) >= TOLERANCE) { if (e < num_expected_colors-1) goto next_color; /* test the next expected color */ printf("Probe color at (%i,%i), ", offx+x, offy+y); printf("Expected: %.3f, %.3f, %.3f, %.3f, ", expected[e*4], expected[e*4+1], expected[e*4+2], expected[e*4+3]); printf("Got: %.3f, %.3f, %.3f, %.3f\n", probe[0], probe[1], probe[2], probe[2]); pass = false; goto done; } } } } break; /* this color was successful */ next_color:; } done: free(pixels); return pass; }
static void vid_dec_FillOutput(vid_dec_PrivateType *priv, struct pipe_video_buffer *buf, OMX_BUFFERHEADERTYPE* output) { omx_base_PortType *port = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; struct pipe_sampler_view **views; struct pipe_transfer *transfer; struct pipe_box box = { }; uint8_t *src, *dst; views = buf->get_sampler_view_planes(buf); dst = output->pBuffer; box.width = def->nFrameWidth; box.height = def->nFrameHeight; box.depth = 1; src = priv->pipe->transfer_map(priv->pipe, views[0]->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); util_copy_rect(dst, views[0]->texture->format, def->nStride, 0, 0, box.width, box.height, src, transfer->stride, 0, 0); pipe_transfer_unmap(priv->pipe, transfer); dst = ((uint8_t*)output->pBuffer) + (def->nStride * box.height); box.width = def->nFrameWidth / 2; box.height = def->nFrameHeight / 2; src = priv->pipe->transfer_map(priv->pipe, views[1]->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); util_copy_rect(dst, views[1]->texture->format, def->nStride, 0, 0, box.width, box.height, src, transfer->stride, 0, 0); pipe_transfer_unmap(priv->pipe, transfer); }
void u_upload_unmap( struct u_upload_mgr *upload ) { if (upload->transfer) { struct pipe_box *box = &upload->transfer->box; if (upload->offset > box->x) { pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer, box->x, upload->offset - box->x); } pipe_transfer_unmap(upload->pipe, upload->transfer); pipe_transfer_destroy(upload->pipe, upload->transfer); upload->transfer = NULL; upload->map = NULL; } }
HRESULT NINE_WINAPI NineVolume9_UnlockBox( struct NineVolume9 *This ) { DBG("This=%p lock_count=%u\n", This, This->lock_count); user_assert(This->lock_count, D3DERR_INVALIDCALL); if (This->transfer) { This->pipe->transfer_unmap(This->pipe, This->transfer); This->transfer = NULL; } --This->lock_count; if (This->data_conversion) { struct pipe_transfer *transfer; uint8_t *dst = This->data; struct pipe_box box; u_box_3d(0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Depth, &box); if (!dst) { dst = This->pipe->transfer_map(This->pipe, This->resource, This->level, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE, &box, &transfer); if (!dst) return D3D_OK; } (void) util_format_translate_3d(This->info.format, dst, This->data ? This->stride : transfer->stride, This->data ? This->layer_stride : transfer->layer_stride, 0, 0, 0, This->format_conversion, This->data_conversion, This->stride_conversion, This->layer_stride_conversion, 0, 0, 0, This->desc.Width, This->desc.Height, This->desc.Height); if (!This->data) pipe_transfer_unmap(This->pipe, transfer); } return D3D_OK; }
/** * Called via ctx->Driver.UnmapRenderbuffer. */ static void st_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { struct st_context *st = st_context(ctx); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; if (strb->software) { /* software-allocated renderbuffer (probably an accum buffer) */ return; } pipe_transfer_unmap(pipe, strb->transfer); strb->transfer = NULL; }
/** * Create a texture which represents a bitmap image. */ static struct pipe_resource * make_bitmap_texture(struct gl_context *ctx, GLsizei width, GLsizei height, const struct gl_pixelstore_attrib *unpack, const GLubyte *bitmap) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_transfer *transfer; ubyte *dest; struct pipe_resource *pt; /* PBO source... */ bitmap = _mesa_map_pbo_source(ctx, unpack, bitmap); if (!bitmap) { return NULL; } /** * Create texture to hold bitmap pattern. */ pt = st_texture_create(st, st->internal_target, st->bitmap.tex_format, 0, width, height, 1, 1, PIPE_BIND_SAMPLER_VIEW); if (!pt) { _mesa_unmap_pbo_source(ctx, unpack); return NULL; } transfer = pipe_get_transfer(st->pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, width, height); dest = pipe_transfer_map(pipe, transfer); /* Put image into texture transfer */ memset(dest, 0xff, height * transfer->stride); unpack_bitmap(st, 0, 0, width, height, unpack, bitmap, dest, transfer->stride); _mesa_unmap_pbo_source(ctx, unpack); /* Release transfer */ pipe_transfer_unmap(pipe, transfer); pipe->transfer_destroy(pipe, transfer); return pt; }
static void pipe_unmap(struct gralloc_drm_drv_t *drv, struct gralloc_drm_bo_t *bo) { struct pipe_manager *pm = (struct pipe_manager *) drv; struct pipe_buffer *buf = (struct pipe_buffer *) bo; pthread_mutex_lock(&pm->mutex); assert(buf && buf->transfer); pipe_transfer_unmap(pm->context, buf->transfer); pipe_transfer_destroy(pm->context, buf->transfer); buf->transfer = NULL; pm->context->flush(pm->context, NULL); pthread_mutex_unlock(&pm->mutex); }
void st_texture_image_unmap(struct st_context *st, struct st_texture_image *stImage, unsigned slice) { struct pipe_context *pipe = st->pipe; struct st_texture_object *stObj = st_texture_object(stImage->base.TexObject); struct pipe_transfer **transfer; if (stObj->base.Immutable) slice += stObj->base.MinLayer; transfer = &stImage->transfer[slice + stImage->base.Face].transfer; DBG("%s\n", __FUNCTION__); pipe_transfer_unmap(pipe, *transfer); *transfer = NULL; }
void u_default_texture_subdata(struct pipe_context *pipe, struct pipe_resource *resource, unsigned level, unsigned usage, const struct pipe_box *box, const void *data, unsigned stride, unsigned layer_stride) { struct pipe_transfer *transfer = NULL; const uint8_t *src_data = data; uint8_t *map = NULL; assert(!(usage & PIPE_TRANSFER_READ)); /* the write flag is implicit by the nature of texture_subdata */ usage |= PIPE_TRANSFER_WRITE; /* texture_subdata implicitly discards the rewritten buffer range */ usage |= PIPE_TRANSFER_DISCARD_RANGE; map = pipe->transfer_map(pipe, resource, level, usage, box, &transfer); if (!map) return; util_copy_box(map, resource->format, transfer->stride, /* bytes */ transfer->layer_stride, /* bytes */ 0, 0, 0, box->width, box->height, box->depth, src_data, stride, /* bytes */ layer_stride, /* bytes */ 0, 0, 0); pipe_transfer_unmap(pipe, transfer); }
static void upload_unmap_internal(struct u_upload_mgr *upload, boolean destroying) { if (!destroying && upload->map_persistent) return; if (upload->transfer) { struct pipe_box *box = &upload->transfer->box; if (!upload->map_persistent && (int) upload->offset > box->x) { pipe_buffer_flush_mapped_range(upload->pipe, upload->transfer, box->x, upload->offset - box->x); } pipe_transfer_unmap(upload->pipe, upload->transfer); upload->transfer = NULL; upload->map = NULL; } }
/** * Upload data to a rectangular sub-region. Lots of choices how to do this: * * - memcpy by span to current destination * - upload data as new buffer and blit * * Currently always memcpy. */ static void st_surface_data(struct pipe_context *pipe, struct pipe_transfer *dst, unsigned dstx, unsigned dsty, const void *src, unsigned src_stride, unsigned srcx, unsigned srcy, unsigned width, unsigned height) { void *map = pipe_transfer_map(pipe, dst); assert(dst->resource); util_copy_rect(map, dst->resource->format, dst->stride, dstx, dsty, width, height, src, src_stride, srcx, srcy); pipe_transfer_unmap(pipe, dst); }
/** * Update the pixelmap texture with the contents of the R/G/B/A pixel maps. */ static void load_color_map_texture(struct gl_context *ctx, struct pipe_resource *pt) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_transfer *transfer; const GLuint rSize = ctx->PixelMaps.RtoR.Size; const GLuint gSize = ctx->PixelMaps.GtoG.Size; const GLuint bSize = ctx->PixelMaps.BtoB.Size; const GLuint aSize = ctx->PixelMaps.AtoA.Size; const uint texSize = pt->width0; uint *dest; uint i, j; dest = (uint *) pipe_transfer_map(pipe, pt, 0, 0, PIPE_TRANSFER_WRITE, 0, 0, texSize, texSize, &transfer); /* Pack four 1D maps into a 2D texture: * R map is placed horizontally, indexed by S, in channel 0 * G map is placed vertically, indexed by T, in channel 1 * B map is placed horizontally, indexed by S, in channel 2 * A map is placed vertically, indexed by T, in channel 3 */ for (i = 0; i < texSize; i++) { for (j = 0; j < texSize; j++) { union util_color uc; int k = (i * texSize + j); float rgba[4]; rgba[0] = ctx->PixelMaps.RtoR.Map[j * rSize / texSize]; rgba[1] = ctx->PixelMaps.GtoG.Map[i * gSize / texSize]; rgba[2] = ctx->PixelMaps.BtoB.Map[j * bSize / texSize]; rgba[3] = ctx->PixelMaps.AtoA.Map[i * aSize / texSize]; util_pack_color(rgba, pt->format, &uc); *(dest + k) = uc.ui[0]; } } pipe_transfer_unmap(pipe, transfer); }
/** * Copy image data from a VdpOutputSurface to application memory in the * surface's native format. */ VdpStatus vlVdpOutputSurfaceGetBitsNative(VdpOutputSurface surface, VdpRect const *source_rect, void *const *destination_data, uint32_t const *destination_pitches) { vlVdpOutputSurface *vlsurface; struct pipe_context *pipe; struct pipe_resource *res; struct pipe_box box; struct pipe_transfer *transfer; uint8_t *map; vlsurface = vlGetDataHTAB(surface); if (!vlsurface) return VDP_STATUS_INVALID_HANDLE; pipe = vlsurface->device->context; if (!pipe) return VDP_STATUS_INVALID_HANDLE; pipe_mutex_lock(vlsurface->device->mutex); vlVdpResolveDelayedRendering(vlsurface->device, NULL, NULL); res = vlsurface->sampler_view->texture; box = RectToPipeBox(source_rect, res); map = pipe->transfer_map(pipe, res, 0, PIPE_TRANSFER_READ, &box, &transfer); if (!map) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } util_copy_rect(*destination_data, res->format, *destination_pitches, 0, 0, box.width, box.height, map, transfer->stride, 0, 0); pipe_transfer_unmap(pipe, transfer); pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_OK; }
static void vid_dec_FillOutput(vid_dec_PrivateType *priv, struct pipe_video_buffer *buf, OMX_BUFFERHEADERTYPE* output) { omx_base_PortType *port = priv->ports[OMX_BASE_FILTER_OUTPUTPORT_INDEX]; OMX_VIDEO_PORTDEFINITIONTYPE *def = &port->sPortParam.format.video; struct pipe_sampler_view **views; unsigned i, j; unsigned width, height; views = buf->get_sampler_view_planes(buf); for (i = 0; i < 2 /* NV12 */; i++) { if (!views[i]) continue; width = def->nFrameWidth; height = def->nFrameHeight; vl_video_buffer_adjust_size(&width, &height, i, buf->chroma_format, buf->interlaced); for (j = 0; j < views[i]->texture->array_size; ++j) { struct pipe_box box = {0, 0, j, width, height, 1}; struct pipe_transfer *transfer; uint8_t *map, *dst; map = priv->pipe->transfer_map(priv->pipe, views[i]->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); if (!map) return; dst = ((uint8_t*)output->pBuffer + output->nOffset) + j * def->nStride + i * def->nFrameWidth * def->nFrameHeight; util_copy_rect(dst, views[i]->texture->format, def->nStride * views[i]->texture->array_size, 0, 0, box.width, box.height, map, transfer->stride, 0, 0); pipe_transfer_unmap(priv->pipe, transfer); } } }
static void drisw_update_tex_buffer(struct dri_drawable *drawable, struct dri_context *ctx, struct pipe_resource *res) { __DRIdrawable *dPriv = drawable->dPriv; struct st_context *st_ctx = (struct st_context *)ctx->st; struct pipe_context *pipe = st_ctx->pipe; struct pipe_transfer *transfer; char *map; int x, y, w, h; int ximage_stride, line; int cpp = util_format_get_blocksize(res->format); get_drawable_info(dPriv, &x, &y, &w, &h); map = pipe_transfer_map(pipe, res, 0, 0, // level, layer, PIPE_TRANSFER_WRITE, x, y, w, h, &transfer); /* Copy the Drawable content to the mapped texture buffer */ get_image(dPriv, x, y, w, h, map); /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. get_image() has a pitch rounded up to 4 bytes. */ ximage_stride = ((w * cpp) + 3) & -4; for (line = h-1; line; --line) { memmove(&map[line * transfer->stride], &map[line * ximage_stride], ximage_stride); } pipe_transfer_unmap(pipe, transfer); }
PUBLIC void XMesaBindTexImage(Display *dpy, XMesaBuffer drawable, int buffer, const int *attrib_list) { struct st_context_iface *st = stapi->get_current(stapi); struct st_framebuffer_iface* stfbi = drawable->stfb; struct pipe_resource *res; int x, y, w, h; enum st_attachment_type st_attachment = xmesa_attachment_type(buffer); x = 0; y = 0; w = drawable->width; h = drawable->height; /* We need to validate our attachments before using them, * in case the texture doesn't exist yet. */ xmesa_st_framebuffer_validate_textures(stfbi, w, h, 1 << st_attachment); res = xmesa_get_attachment(stfbi, st_attachment); if (res) { struct pipe_context* pipe = xmesa_get_context(stfbi); enum pipe_format internal_format = res->format; struct pipe_transfer *tex_xfer; char *map; int line, ximage_stride; XImage *img; internal_format = choose_pixel_format(drawable->xm_visual); tex_xfer = pipe_get_transfer(pipe, res, 0, 0, /* level, layer */ PIPE_TRANSFER_WRITE, x, y, w, h); if (!tex_xfer) return; /* Grab the XImage that we want to turn into a texture. */ img = XGetImage(dpy, drawable->ws.drawable, x, y, w, h, AllPlanes, ZPixmap); if (!img) { pipe_transfer_destroy(pipe, tex_xfer); return; } map = pipe_transfer_map(pipe, tex_xfer); if (!map) { pipe_transfer_destroy(pipe, tex_xfer); return; } /* The pipe transfer has a pitch rounded up to the nearest 64 pixels. We assume 32 bit pixels. */ ximage_stride = w * 4; for (line = 0; line < h; line++) memcpy(&map[line * tex_xfer->stride], &img->data[line * ximage_stride], ximage_stride); pipe_transfer_unmap(pipe, tex_xfer); pipe_transfer_destroy(pipe, tex_xfer); st->teximage(st, ST_TEXTURE_2D, 0, /* level */ internal_format, res, FALSE /* no mipmap */); } }
/** * Copy image data from a VdpVideoSurface to application memory in a specified * YCbCr format. */ VdpStatus vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface, VdpYCbCrFormat destination_ycbcr_format, void *const *destination_data, uint32_t const *destination_pitches) { vlVdpSurface *vlsurface; struct pipe_context *pipe; enum pipe_format format, buffer_format; struct pipe_sampler_view **sampler_views; enum getbits_conversion conversion = CONVERSION_NONE; unsigned i, j; vlsurface = vlGetDataHTAB(surface); if (!vlsurface) return VDP_STATUS_INVALID_HANDLE; pipe = vlsurface->device->context; if (!pipe) return VDP_STATUS_INVALID_HANDLE; if (!destination_data || !destination_pitches) return VDP_STATUS_INVALID_POINTER; format = FormatYCBCRToPipe(destination_ycbcr_format); if (format == PIPE_FORMAT_NONE) return VDP_STATUS_INVALID_Y_CB_CR_FORMAT; if (vlsurface->video_buffer == NULL) return VDP_STATUS_INVALID_VALUE; buffer_format = vlsurface->video_buffer->buffer_format; if (format != buffer_format) { if (format == PIPE_FORMAT_YV12 && buffer_format == PIPE_FORMAT_NV12) conversion = CONVERSION_NV12_TO_YV12; else if (format == PIPE_FORMAT_NV12 && buffer_format == PIPE_FORMAT_YV12) conversion = CONVERSION_YV12_TO_NV12; else if ((format == PIPE_FORMAT_YUYV && buffer_format == PIPE_FORMAT_UYVY) || (format == PIPE_FORMAT_UYVY && buffer_format == PIPE_FORMAT_YUYV)) conversion = CONVERSION_SWAP_YUYV_UYVY; else return VDP_STATUS_NO_IMPLEMENTATION; } pipe_mutex_lock(vlsurface->device->mutex); sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer); if (!sampler_views) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } for (i = 0; i < 3; ++i) { unsigned width, height; struct pipe_sampler_view *sv = sampler_views[i]; if (!sv) continue; vlVdpVideoSurfaceSize(vlsurface, i, &width, &height); for (j = 0; j < sv->texture->array_size; ++j) { struct pipe_box box = { 0, 0, j, width, height, 1 }; struct pipe_transfer *transfer; uint8_t *map; map = pipe->transfer_map(pipe, sv->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); if (!map) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } if (conversion == CONVERSION_NV12_TO_YV12 && i == 1) { u_copy_nv12_to_yv12(destination_data, destination_pitches, i, j, transfer->stride, sv->texture->array_size, map, box.width, box.height); } else if (conversion == CONVERSION_YV12_TO_NV12 && i > 0) { u_copy_yv12_to_nv12(destination_data, destination_pitches, i, j, transfer->stride, sv->texture->array_size, map, box.width, box.height); } else if (conversion == CONVERSION_SWAP_YUYV_UYVY) { u_copy_swap422_packed(destination_data, destination_pitches, i, j, transfer->stride, sv->texture->array_size, map, box.width, box.height); } else { util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format, destination_pitches[i] * sv->texture->array_size, 0, 0, box.width, box.height, map, transfer->stride, 0, 0); } pipe_transfer_unmap(pipe, transfer); } } pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_OK; }
VAStatus vlVaGetImage(VADriverContextP ctx, VASurfaceID surface, int x, int y, unsigned int width, unsigned int height, VAImageID image) { vlVaDriver *drv; vlVaSurface *surf; vlVaBuffer *img_buf; VAImage *vaimage; struct pipe_sampler_view **views; enum pipe_format format; bool convert = false; void *data[3]; unsigned pitches[3], i, j; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); pipe_mutex_lock(drv->mutex); surf = handle_table_get(drv->htab, surface); if (!surf || !surf->buffer) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_SURFACE; } vaimage = handle_table_get(drv->htab, image); if (!vaimage) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_IMAGE; } img_buf = handle_table_get(drv->htab, vaimage->buf); if (!img_buf) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_BUFFER; } format = VaFourccToPipeFormat(vaimage->format.fourcc); if (format == PIPE_FORMAT_NONE) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_OPERATION_FAILED; } if (format != surf->buffer->buffer_format) { /* support NV12 to YV12 and IYUV conversion now only */ if ((format == PIPE_FORMAT_YV12 && surf->buffer->buffer_format == PIPE_FORMAT_NV12) || (format == PIPE_FORMAT_IYUV && surf->buffer->buffer_format == PIPE_FORMAT_NV12)) convert = true; else { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_OPERATION_FAILED; } } views = surf->buffer->get_sampler_view_planes(surf->buffer); if (!views) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_OPERATION_FAILED; } for (i = 0; i < vaimage->num_planes; i++) { data[i] = img_buf->data + vaimage->offsets[i]; pitches[i] = vaimage->pitches[i]; } if (vaimage->format.fourcc == VA_FOURCC('I','4','2','0')) { void *tmp_d; unsigned tmp_p; tmp_d = data[1]; data[1] = data[2]; data[2] = tmp_d; tmp_p = pitches[1]; pitches[1] = pitches[2]; pitches[2] = tmp_p; } for (i = 0; i < vaimage->num_planes; i++) { unsigned width, height; if (!views[i]) continue; vlVaVideoSurfaceSize(surf, i, &width, &height); for (j = 0; j < views[i]->texture->array_size; ++j) { struct pipe_box box = {0, 0, j, width, height, 1}; struct pipe_transfer *transfer; uint8_t *map; map = drv->pipe->transfer_map(drv->pipe, views[i]->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); if (!map) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_OPERATION_FAILED; } if (i == 1 && convert) { u_copy_nv12_to_yv12(data, pitches, i, j, transfer->stride, views[i]->texture->array_size, map, box.width, box.height); } else { util_copy_rect(data[i] + pitches[i] * j, views[i]->texture->format, pitches[i] * views[i]->texture->array_size, 0, 0, box.width, box.height, map, transfer->stride, 0, 0); } pipe_transfer_unmap(drv->pipe, transfer); } } pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
/** * Copy image data from a VdpVideoSurface to application memory in a specified * YCbCr format. */ VdpStatus vlVdpVideoSurfaceGetBitsYCbCr(VdpVideoSurface surface, VdpYCbCrFormat destination_ycbcr_format, void *const *destination_data, uint32_t const *destination_pitches) { vlVdpSurface *vlsurface; struct pipe_context *pipe; enum pipe_format format; struct pipe_sampler_view **sampler_views; unsigned i, j; vlsurface = vlGetDataHTAB(surface); if (!vlsurface) return VDP_STATUS_INVALID_HANDLE; pipe = vlsurface->device->context; if (!pipe) return VDP_STATUS_INVALID_HANDLE; format = FormatYCBCRToPipe(destination_ycbcr_format); if (format == PIPE_FORMAT_NONE) return VDP_STATUS_INVALID_Y_CB_CR_FORMAT; if (vlsurface->video_buffer == NULL || format != vlsurface->video_buffer->buffer_format) return VDP_STATUS_NO_IMPLEMENTATION; /* TODO We don't support conversion (yet) */ pipe_mutex_lock(vlsurface->device->mutex); sampler_views = vlsurface->video_buffer->get_sampler_view_planes(vlsurface->video_buffer); if (!sampler_views) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } for (i = 0; i < 3; ++i) { unsigned width, height; struct pipe_sampler_view *sv = sampler_views[i]; if (!sv) continue; vlVdpVideoSurfaceSize(vlsurface, i, &width, &height); for (j = 0; j < sv->texture->array_size; ++j) { struct pipe_box box = { 0, 0, j, width, height, 1 }; struct pipe_transfer *transfer; uint8_t *map; map = pipe->transfer_map(pipe, sv->texture, 0, PIPE_TRANSFER_READ, &box, &transfer); if (!map) { pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_RESOURCES; } util_copy_rect(destination_data[i] + destination_pitches[i] * j, sv->texture->format, destination_pitches[i] * sv->texture->array_size, 0, 0, box.width, box.height, map, transfer->stride, 0, 0); pipe_transfer_unmap(pipe, transfer); } } pipe_mutex_unlock(vlsurface->device->mutex); return VDP_STATUS_OK; }
/* When this function is called, we have already checked * The copy regions fit the surfaces */ void NineSurface9_CopyMemToDefault( struct NineSurface9 *This, struct NineSurface9 *From, const POINT *pDestPoint, const RECT *pSourceRect ) { struct pipe_context *pipe = This->pipe; struct pipe_transfer *transfer = NULL; struct pipe_resource *r_dst = This->base.resource; struct pipe_box dst_box; uint8_t *map = NULL; int src_x, src_y, dst_x, dst_y, copy_width, copy_height; assert(This->base.pool == D3DPOOL_DEFAULT && From->base.pool == D3DPOOL_SYSTEMMEM); if (pDestPoint) { dst_x = pDestPoint->x; dst_y = pDestPoint->y; } else { dst_x = 0; dst_y = 0; } if (pSourceRect) { src_x = pSourceRect->left; src_y = pSourceRect->top; copy_width = pSourceRect->right - pSourceRect->left; copy_height = pSourceRect->bottom - pSourceRect->top; } else { src_x = 0; src_y = 0; copy_width = From->desc.Width; copy_height = From->desc.Height; } u_box_2d_zslice(dst_x, dst_y, This->layer, copy_width, copy_height, &dst_box); map = pipe->transfer_map(pipe, r_dst, This->level, PIPE_TRANSFER_WRITE | PIPE_TRANSFER_DISCARD_RANGE, &dst_box, &transfer); if (!map) return; /* Note: if formats are the sames, it will revert * to normal memcpy */ (void) util_format_translate(r_dst->format, map, transfer->stride, 0, 0, From->base.info.format, From->data, From->stride, src_x, src_y, copy_width, copy_height); pipe_transfer_unmap(pipe, transfer); if (This->data_conversion) (void) util_format_translate(This->format_conversion, This->data_conversion, This->stride_conversion, dst_x, dst_y, From->base.info.format, From->data, From->stride, src_x, src_y, copy_width, copy_height); NineSurface9_MarkContainerDirty(This); }
/** * This uses a blit to copy the read buffer to a texture format which matches * the format and type combo and then a fast read-back is done using memcpy. * We can do arbitrary X/Y/Z/W/0/1 swizzling here as long as there is * a format which matches the swizzling. * * If such a format isn't available, we fall back to _mesa_readpixels. * * NOTE: Some drivers use a blit to convert between tiled and linear * texture layouts during texture uploads/downloads, so the blit * we do here should be free in such cases. */ static void st_readpixels(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, const struct gl_pixelstore_attrib *pack, GLvoid *pixels) { struct st_context *st = st_context(ctx); struct gl_renderbuffer *rb = _mesa_get_read_renderbuffer_for_format(ctx, format); struct st_renderbuffer *strb = st_renderbuffer(rb); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct pipe_resource *src; struct pipe_resource *dst = NULL; struct pipe_resource dst_templ; enum pipe_format dst_format, src_format; struct pipe_blit_info blit; unsigned bind = PIPE_BIND_TRANSFER_READ; struct pipe_transfer *tex_xfer; ubyte *map = NULL; /* Validate state (to be sure we have up-to-date framebuffer surfaces) * and flush the bitmap cache prior to reading. */ st_validate_state(st); st_flush_bitmap_cache(st); if (!st->prefer_blit_based_texture_transfer) { goto fallback; } /* This must be done after state validation. */ src = strb->texture; /* XXX Fallback for depth-stencil formats due to an incomplete * stencil blit implementation in some drivers. */ if (format == GL_DEPTH_STENCIL) { goto fallback; } /* We are creating a texture of the size of the region being read back. * Need to check for NPOT texture support. */ if (!screen->get_param(screen, PIPE_CAP_NPOT_TEXTURES) && (!util_is_power_of_two(width) || !util_is_power_of_two(height))) { goto fallback; } /* If the base internal format and the texture format don't match, we have * to use the slow path. */ if (rb->_BaseFormat != _mesa_get_format_base_format(rb->Format)) { goto fallback; } /* See if the texture format already matches the format and type, * in which case the memcpy-based fast path will likely be used and * we don't have to blit. */ if (_mesa_format_matches_format_and_type(rb->Format, format, type, pack->SwapBytes)) { goto fallback; } if (_mesa_readpixels_needs_slow_path(ctx, format, type, GL_TRUE)) { goto fallback; } /* Convert the source format to what is expected by ReadPixels * and see if it's supported. */ src_format = util_format_linear(src->format); src_format = util_format_luminance_to_red(src_format); src_format = util_format_intensity_to_red(src_format); if (!src_format || !screen->is_format_supported(screen, src_format, src->target, src->nr_samples, PIPE_BIND_SAMPLER_VIEW)) { goto fallback; } if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL) bind |= PIPE_BIND_DEPTH_STENCIL; else bind |= PIPE_BIND_RENDER_TARGET; /* Choose the destination format by finding the best match * for the format+type combo. */ dst_format = st_choose_matching_format(screen, bind, format, type, pack->SwapBytes); if (dst_format == PIPE_FORMAT_NONE) { goto fallback; } /* create the destination texture */ memset(&dst_templ, 0, sizeof(dst_templ)); dst_templ.target = PIPE_TEXTURE_2D; dst_templ.format = dst_format; dst_templ.bind = bind; dst_templ.usage = PIPE_USAGE_STAGING; st_gl_texture_dims_to_pipe_dims(GL_TEXTURE_2D, width, height, 1, &dst_templ.width0, &dst_templ.height0, &dst_templ.depth0, &dst_templ.array_size); dst = screen->resource_create(screen, &dst_templ); if (!dst) { goto fallback; } memset(&blit, 0, sizeof(blit)); blit.src.resource = src; blit.src.level = strb->surface->u.tex.level; blit.src.format = src_format; blit.dst.resource = dst; blit.dst.level = 0; blit.dst.format = dst->format; blit.src.box.x = x; blit.dst.box.x = 0; blit.src.box.y = y; blit.dst.box.y = 0; blit.src.box.z = strb->surface->u.tex.first_layer; blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = st_get_blit_mask(rb->_BaseFormat, format); blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { blit.src.box.y = rb->Height - blit.src.box.y; blit.src.box.height = -blit.src.box.height; } /* blit */ st->pipe->blit(st->pipe, &blit); /* map resources */ pixels = _mesa_map_pbo_dest(ctx, pack, pixels); map = pipe_transfer_map_3d(pipe, dst, 0, PIPE_TRANSFER_READ, 0, 0, 0, width, height, 1, &tex_xfer); if (!map) { _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); goto fallback; } /* memcpy data into a user buffer */ { const uint bytesPerRow = width * util_format_get_blocksize(dst_format); GLuint row; for (row = 0; row < (unsigned) height; row++) { GLvoid *dest = _mesa_image_address3d(pack, pixels, width, height, format, type, 0, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } } pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, pack); pipe_resource_reference(&dst, NULL); return; fallback: _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels); }
/** * glGetTexImage() helper: decompress a compressed texture by rendering * a textured quad. Store the results in the user's buffer. */ static void decompress_with_blit(struct gl_context * ctx, GLenum format, GLenum type, GLvoid *pixels, struct gl_texture_image *texImage) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct st_texture_image *stImage = st_texture_image(texImage); struct st_texture_object *stObj = st_texture_object(texImage->TexObject); const GLuint width = texImage->Width; const GLuint height = texImage->Height; struct pipe_resource *dst_texture; struct pipe_blit_info blit; unsigned bind = (PIPE_BIND_RENDER_TARGET | PIPE_BIND_TRANSFER_READ); struct pipe_transfer *tex_xfer; ubyte *map; /* create temp / dest surface */ if (!util_create_rgba_texture(pipe, width, height, bind, &dst_texture)) { _mesa_problem(ctx, "util_create_rgba_texture() failed " "in decompress_with_blit()"); return; } blit.src.resource = stObj->pt; blit.src.level = texImage->Level; blit.src.format = util_format_linear(stObj->pt->format); blit.dst.resource = dst_texture; blit.dst.level = 0; blit.dst.format = dst_texture->format; blit.src.box.x = blit.dst.box.x = 0; blit.src.box.y = blit.dst.box.y = 0; blit.src.box.z = 0; /* XXX compressed array textures? */ blit.dst.box.z = 0; blit.src.box.width = blit.dst.box.width = width; blit.src.box.height = blit.dst.box.height = height; blit.src.box.depth = blit.dst.box.depth = 1; blit.mask = PIPE_MASK_RGBA; blit.filter = PIPE_TEX_FILTER_NEAREST; blit.scissor_enable = FALSE; /* blit/render/decompress */ st->pipe->blit(st->pipe, &blit); pixels = _mesa_map_pbo_dest(ctx, &ctx->Pack, pixels); map = pipe_transfer_map(pipe, dst_texture, 0, 0, PIPE_TRANSFER_READ, 0, 0, width, height, &tex_xfer); if (!map) { goto end; } /* copy/pack data into user buffer */ if (_mesa_format_matches_format_and_type(stImage->base.TexFormat, format, type, ctx->Pack.SwapBytes)) { /* memcpy */ const uint bytesPerRow = width * util_format_get_blocksize(stImage->pt->format); /* map the dst_surface so we can read from it */ GLuint row; for (row = 0; row < height; row++) { GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); memcpy(dest, map, bytesPerRow); map += tex_xfer->stride; } pipe_transfer_unmap(pipe, tex_xfer); } else { /* format translation via floats */ GLuint row; enum pipe_format pformat = util_format_linear(dst_texture->format); GLfloat *rgba; rgba = malloc(width * 4 * sizeof(GLfloat)); if (!rgba) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGetTexImage()"); goto end; } for (row = 0; row < height; row++) { const GLbitfield transferOps = 0x0; /* bypassed for glGetTexImage() */ GLvoid *dest = _mesa_image_address2d(&ctx->Pack, pixels, width, height, format, type, row, 0); if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback format translation\n", __FUNCTION__); /* get float[4] rgba row from surface */ pipe_get_tile_rgba_format(tex_xfer, map, 0, row, width, 1, pformat, rgba); _mesa_pack_rgba_span_float(ctx, width, (GLfloat (*)[4]) rgba, format, type, dest, &ctx->Pack, transferOps); } free(rgba); } end: if (map) pipe_transfer_unmap(pipe, tex_xfer); _mesa_unmap_pbo_dest(ctx, &ctx->Pack); pipe_resource_reference(&dst_texture, NULL); }