static void sp_flush_tile(struct softpipe_tile_cache* tc, unsigned pos) { if (!tc->tile_addrs[pos].bits.invalid) { if (tc->depth_stencil) { pipe_put_tile_raw(tc->pipe, tc->transfer, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->entries[pos]->data.depth32, 0/*STRIDE*/); } else { if (util_format_is_pure_uint(tc->surface->format)) { pipe_put_tile_ui_format(tc->pipe, tc->transfer, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (unsigned *) tc->entries[pos]->data.colorui128); } else if (util_format_is_pure_sint(tc->surface->format)) { pipe_put_tile_i_format(tc->pipe, tc->transfer, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (int *) tc->entries[pos]->data.colori128); } else { pipe_put_tile_rgba_format(tc->pipe, tc->transfer, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (float *) tc->entries[pos]->data.color); } } tc->tile_addrs[pos].bits.invalid = 1; /* mark as empty */ } }
static void st_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy, GLsizei width, GLsizei height, GLint dstx, GLint dsty, GLenum type) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct pipe_screen *screen = pipe->screen; struct st_renderbuffer *rbRead; void *driver_vp, *driver_fp; struct pipe_resource *pt; struct pipe_sampler_view *sv[2]; int num_sampler_view = 1; GLfloat *color; enum pipe_format srcFormat, texFormat; GLboolean invertTex = GL_FALSE; GLint readX, readY, readW, readH; GLuint sample_count; struct gl_pixelstore_attrib pack = ctx->DefaultPacking; struct st_fp_variant *fpv; st_validate_state(st); if (type == GL_STENCIL) { /* can't use texturing to do stencil */ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty); return; } if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type)) return; /* * The subsequent code implements glCopyPixels by copying the source * pixels into a temporary texture that's then applied to a textured quad. * When we draw the textured quad, all the usual per-fragment operations * are handled. */ /* * Get vertex/fragment shaders */ if (type == GL_COLOR) { rbRead = st_get_color_read_renderbuffer(ctx); color = NULL; fpv = get_color_fp_variant(st); driver_fp = fpv->driver_shader; driver_vp = make_passthrough_vertex_shader(st, GL_FALSE); if (st->pixel_xfer.pixelmap_enabled) { sv[1] = st->pixel_xfer.pixelmap_sampler_view; num_sampler_view++; } } else { assert(type == GL_DEPTH); rbRead = st_renderbuffer(ctx->ReadBuffer->_DepthBuffer); color = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; fpv = get_depth_stencil_fp_variant(st, GL_TRUE, GL_FALSE); driver_fp = fpv->driver_shader; driver_vp = make_passthrough_vertex_shader(st, GL_TRUE); } /* update fragment program constants */ st_upload_constants(st, fpv->parameters, PIPE_SHADER_FRAGMENT); if (rbRead->Base.Wrapped) rbRead = st_renderbuffer(rbRead->Base.Wrapped); sample_count = rbRead->texture->nr_samples; /* I believe this would be legal, presumably would need to do a resolve for color, and for depth/stencil spec says to just use one of the depth/stencil samples per pixel? Need some transfer clarifications. */ assert(sample_count < 2); srcFormat = rbRead->texture->format; if (screen->is_format_supported(screen, srcFormat, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW)) { texFormat = srcFormat; } else { /* srcFormat can't be used as a texture format */ if (type == GL_DEPTH) { texFormat = st_choose_format(screen, GL_DEPTH_COMPONENT, GL_NONE, GL_NONE, st->internal_target, sample_count, PIPE_BIND_DEPTH_STENCIL); assert(texFormat != PIPE_FORMAT_NONE); } else { /* default color format */ texFormat = st_choose_format(screen, GL_RGBA, GL_NONE, GL_NONE, st->internal_target, sample_count, PIPE_BIND_SAMPLER_VIEW); assert(texFormat != PIPE_FORMAT_NONE); } } /* Invert src region if needed */ if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) { srcy = ctx->ReadBuffer->Height - srcy - height; invertTex = !invertTex; } /* Clip the read region against the src buffer bounds. * We'll still allocate a temporary buffer/texture for the original * src region size but we'll only read the region which is on-screen. * This may mean that we draw garbage pixels into the dest region, but * that's expected. */ readX = srcx; readY = srcy; readW = width; readH = height; _mesa_clip_readpixels(ctx, &readX, &readY, &readW, &readH, &pack); readW = MAX2(0, readW); readH = MAX2(0, readH); /* alloc temporary texture */ pt = alloc_texture(st, width, height, texFormat); if (!pt) return; sv[0] = st_create_texture_sampler_view(st->pipe, pt); if (!sv[0]) { pipe_resource_reference(&pt, NULL); return; } /* Make temporary texture which is a copy of the src region. */ if (srcFormat == texFormat) { struct pipe_box src_box; u_box_2d(readX, readY, readW, readH, &src_box); /* copy source framebuffer surface into mipmap/texture */ pipe->resource_copy_region(pipe, pt, /* dest tex */ 0, /* dest lvl */ pack.SkipPixels, pack.SkipRows, 0, /* dest pos */ rbRead->texture, /* src tex */ rbRead->rtt_level, /* src lvl */ &src_box); } else { /* CPU-based fallback/conversion */ struct pipe_transfer *ptRead = pipe_get_transfer(st->pipe, rbRead->texture, rbRead->rtt_level, rbRead->rtt_face + rbRead->rtt_slice, PIPE_TRANSFER_READ, readX, readY, readW, readH); struct pipe_transfer *ptTex; enum pipe_transfer_usage transfer_usage; if (ST_DEBUG & DEBUG_FALLBACK) debug_printf("%s: fallback processing\n", __FUNCTION__); if (type == GL_DEPTH && util_format_is_depth_and_stencil(pt->format)) transfer_usage = PIPE_TRANSFER_READ_WRITE; else transfer_usage = PIPE_TRANSFER_WRITE; ptTex = pipe_get_transfer(st->pipe, pt, 0, 0, transfer_usage, 0, 0, width, height); /* copy image from ptRead surface to ptTex surface */ if (type == GL_COLOR) { /* alternate path using get/put_tile() */ GLfloat *buf = (GLfloat *) malloc(width * height * 4 * sizeof(GLfloat)); enum pipe_format readFormat, drawFormat; readFormat = util_format_linear(rbRead->texture->format); drawFormat = util_format_linear(pt->format); pipe_get_tile_rgba_format(pipe, ptRead, 0, 0, readW, readH, readFormat, buf); pipe_put_tile_rgba_format(pipe, ptTex, pack.SkipPixels, pack.SkipRows, readW, readH, drawFormat, buf); free(buf); } else { /* GL_DEPTH */ GLuint *buf = (GLuint *) malloc(width * height * sizeof(GLuint)); pipe_get_tile_z(pipe, ptRead, 0, 0, readW, readH, buf); pipe_put_tile_z(pipe, ptTex, pack.SkipPixels, pack.SkipRows, readW, readH, buf); free(buf); } pipe->transfer_destroy(pipe, ptRead); pipe->transfer_destroy(pipe, ptTex); } /* OK, the texture 'pt' contains the src image/pixels. Now draw a * textured quad with that texture. */ draw_textured_quad(ctx, dstx, dsty, ctx->Current.RasterPos[2], width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY, sv, num_sampler_view, driver_vp, driver_fp, color, invertTex, GL_FALSE, GL_FALSE); pipe_resource_reference(&pt, NULL); pipe_sampler_view_reference(&sv[0], NULL); }
/** * Get a tile from the cache. * \param x, y position of tile, in pixels */ struct softpipe_cached_tile * sp_find_cached_tile(struct softpipe_tile_cache *tc, union tile_address addr ) { struct pipe_transfer *pt = tc->transfer; /* cache pos/entry: */ const int pos = CACHE_POS(addr.bits.x, addr.bits.y); struct softpipe_cached_tile *tile = tc->entries[pos]; if (!tile) { tile = sp_alloc_tile(tc); tc->entries[pos] = tile; } if (addr.value != tc->tile_addrs[pos].value) { assert(pt->resource); if (tc->tile_addrs[pos].bits.invalid == 0) { /* put dirty tile back in framebuffer */ if (tc->depth_stencil) { pipe_put_tile_raw(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tile->data.depth32, 0/*STRIDE*/); } else { if (util_format_is_pure_uint(tc->surface->format)) { pipe_put_tile_ui_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (unsigned *) tile->data.colorui128); } else if (util_format_is_pure_sint(tc->surface->format)) { pipe_put_tile_i_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (int *) tile->data.colori128); } else { pipe_put_tile_rgba_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (float *) tile->data.color); } } } tc->tile_addrs[pos] = addr; if (is_clear_flag_set(tc->clear_flags, addr)) { /* don't get tile from framebuffer, just clear it */ if (tc->depth_stencil) { clear_tile(tile, pt->resource->format, tc->clear_val); } else { clear_tile_rgba(tile, pt->resource->format, &tc->clear_color); } clear_clear_flag(tc->clear_flags, addr); } else { /* get new tile data from transfer */ if (tc->depth_stencil) { pipe_get_tile_raw(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tile->data.depth32, 0/*STRIDE*/); } else { if (util_format_is_pure_uint(tc->surface->format)) { pipe_get_tile_ui_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (unsigned *) tile->data.colorui128); } else if (util_format_is_pure_sint(tc->surface->format)) { pipe_get_tile_i_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (int *) tile->data.colori128); } else { pipe_get_tile_rgba_format(tc->pipe, pt, tc->tile_addrs[pos].bits.x * TILE_SIZE, tc->tile_addrs[pos].bits.y * TILE_SIZE, TILE_SIZE, TILE_SIZE, tc->surface->format, (float *) tile->data.color); } } } } tc->last_tile = tile; tc->last_tile_addr = addr; return tile; }