/** * Prepare the renderer for textured drawing. */ VGboolean renderer_drawtex_begin(struct renderer *renderer, struct pipe_sampler_view *src) { assert(renderer->state == RENDERER_STATE_INIT); if (!renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW)) return VG_FALSE; cso_save_blend(renderer->cso); cso_save_samplers(renderer->cso); cso_save_fragment_sampler_views(renderer->cso); cso_save_fragment_shader(renderer->cso); cso_save_vertex_shader(renderer->cso); renderer_set_blend(renderer, ~0); renderer_set_samplers(renderer, 1, &src); renderer_set_fs(renderer, RENDERER_FS_TEXTURE); renderer_set_vs(renderer, RENDERER_VS_TEXTURE); renderer_set_mvp(renderer, NULL); /* remember the texture size */ renderer->u.drawtex.tex_width = src->texture->width0; renderer->u.drawtex.tex_height = src->texture->height0; renderer->state = RENDERER_STATE_DRAWTEX; return VG_TRUE; }
/** * Save all the CSO state items specified by the state_mask bitmask * of CSO_BIT_x flags. */ void cso_save_state(struct cso_context *cso, unsigned state_mask) { assert(cso->saved_state == 0); cso->saved_state = state_mask; if (state_mask & CSO_BIT_AUX_VERTEX_BUFFER_SLOT) cso_save_aux_vertex_buffer_slot(cso); if (state_mask & CSO_BIT_BLEND) cso_save_blend(cso); if (state_mask & CSO_BIT_DEPTH_STENCIL_ALPHA) cso_save_depth_stencil_alpha(cso); if (state_mask & CSO_BIT_FRAGMENT_SAMPLERS) cso_save_fragment_samplers(cso); if (state_mask & CSO_BIT_FRAGMENT_SAMPLER_VIEWS) cso_save_fragment_sampler_views(cso); if (state_mask & CSO_BIT_FRAGMENT_SHADER) cso_save_fragment_shader(cso); if (state_mask & CSO_BIT_FRAMEBUFFER) cso_save_framebuffer(cso); if (state_mask & CSO_BIT_GEOMETRY_SHADER) cso_save_geometry_shader(cso); if (state_mask & CSO_BIT_MIN_SAMPLES) cso_save_min_samples(cso); if (state_mask & CSO_BIT_RASTERIZER) cso_save_rasterizer(cso); if (state_mask & CSO_BIT_RENDER_CONDITION) cso_save_render_condition(cso); if (state_mask & CSO_BIT_SAMPLE_MASK) cso_save_sample_mask(cso); if (state_mask & CSO_BIT_STENCIL_REF) cso_save_stencil_ref(cso); if (state_mask & CSO_BIT_STREAM_OUTPUTS) cso_save_stream_outputs(cso); if (state_mask & CSO_BIT_TESSCTRL_SHADER) cso_save_tessctrl_shader(cso); if (state_mask & CSO_BIT_TESSEVAL_SHADER) cso_save_tesseval_shader(cso); if (state_mask & CSO_BIT_VERTEX_ELEMENTS) cso_save_vertex_elements(cso); if (state_mask & CSO_BIT_VERTEX_SHADER) cso_save_vertex_shader(cso); if (state_mask & CSO_BIT_VIEWPORT) cso_save_viewport(cso); if (state_mask & CSO_BIT_PAUSE_QUERIES) cso->pipe->set_active_query_state(cso->pipe, false); }
/** * Prepare the renderer for copying. */ VGboolean renderer_copy_begin(struct renderer *renderer, struct pipe_surface *dst, VGboolean y0_top, struct pipe_sampler_view *src) { assert(renderer->state == RENDERER_STATE_INIT); /* sanity check */ if (!renderer_can_support(renderer, dst->texture, PIPE_BIND_RENDER_TARGET) || !renderer_can_support(renderer, src->texture, PIPE_BIND_SAMPLER_VIEW)) return VG_FALSE; cso_save_framebuffer(renderer->cso); cso_save_viewport(renderer->cso); cso_save_blend(renderer->cso); cso_save_samplers(renderer->cso); cso_save_fragment_sampler_views(renderer->cso); cso_save_fragment_shader(renderer->cso); cso_save_vertex_shader(renderer->cso); renderer_set_target(renderer, dst, NULL, y0_top); renderer_set_blend(renderer, ~0); renderer_set_samplers(renderer, 1, &src); renderer_set_fs(renderer, RENDERER_FS_TEXTURE); renderer_set_vs(renderer, RENDERER_VS_TEXTURE); renderer_set_mvp(renderer, NULL); /* remember the texture size */ renderer->u.copy.tex_width = src->texture->width0; renderer->u.copy.tex_height = src->texture->height0; renderer->state = RENDERER_STATE_COPY; return VG_TRUE; }
/** * Render a glBitmap by drawing a textured quad */ static void draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, struct pipe_sampler_view *sv, const GLfloat *color) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; struct st_fp_variant *fpv; struct st_fp_variant_key key; GLuint maxSize; GLuint offset; struct pipe_resource *vbuf = NULL; memset(&key, 0, sizeof(key)); key.st = st->has_shareable_shaders ? NULL : st; key.bitmap = GL_TRUE; key.clamp_color = st->clamp_frag_color_in_shader && st->ctx->Color._ClampFragmentColor; fpv = st_get_fp_variant(st, st->fp, &key); /* As an optimization, Mesa's fragment programs will sometimes get the * primary color from a statevar/constant rather than a varying variable. * when that's the case, we need to ensure that we use the 'color' * parameter and not the current attribute color (which may have changed * through glRasterPos and state validation. * So, we force the proper color here. Not elegant, but it works. */ { GLfloat colorSave[4]; COPY_4V(colorSave, ctx->Current.Attrib[VERT_ATTRIB_COLOR0]); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], color); st_upload_constants(st, st->fp->Base.Base.Parameters, PIPE_SHADER_FRAGMENT); COPY_4V(ctx->Current.Attrib[VERT_ATTRIB_COLOR0], colorSave); } /* limit checks */ /* XXX if the bitmap is larger than the max texture size, break * it up into chunks. */ maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); assert(width <= (GLsizei)maxSize); assert(height <= (GLsizei)maxSize); cso_save_rasterizer(cso); cso_save_fragment_samplers(cso); cso_save_fragment_sampler_views(cso); cso_save_viewport(cso); cso_save_fragment_shader(cso); cso_save_stream_outputs(cso); cso_save_vertex_shader(cso); cso_save_tessctrl_shader(cso); cso_save_tesseval_shader(cso); cso_save_geometry_shader(cso); cso_save_vertex_elements(cso); cso_save_aux_vertex_buffer_slot(cso); /* rasterizer state: just scissor */ st->bitmap.rasterizer.scissor = ctx->Scissor.EnableFlags & 1; cso_set_rasterizer(cso, &st->bitmap.rasterizer); /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, fpv->driver_shader); /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, st->bitmap.vs); /* disable other shaders */ cso_set_tessctrl_shader_handle(cso, NULL); cso_set_tesseval_shader_handle(cso, NULL); cso_set_geometry_shader_handle(cso, NULL); /* user samplers, plus our bitmap sampler */ { struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_samplers[PIPE_SHADER_FRAGMENT]); uint i; for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++) { samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i]; } samplers[fpv->bitmap_sampler] = &st->bitmap.samplers[sv->texture->target != PIPE_TEXTURE_RECT]; cso_set_samplers(cso, PIPE_SHADER_FRAGMENT, num, (const struct pipe_sampler_state **) samplers); } /* user textures, plus the bitmap texture */ { struct pipe_sampler_view *sampler_views[PIPE_MAX_SAMPLERS]; uint num = MAX2(fpv->bitmap_sampler + 1, st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]); memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT], sizeof(sampler_views)); sampler_views[fpv->bitmap_sampler] = sv; cso_set_sampler_views(cso, PIPE_SHADER_FRAGMENT, num, sampler_views); } /* viewport state: viewport matching window dims */ { const GLboolean invert = st->state.fb_orientation == Y_0_TOP; const GLfloat width = (GLfloat)st->state.framebuffer.width; const GLfloat height = (GLfloat)st->state.framebuffer.height; struct pipe_viewport_state vp; vp.scale[0] = 0.5f * width; vp.scale[1] = height * (invert ? -0.5f : 0.5f); vp.scale[2] = 0.5f; vp.translate[0] = 0.5f * width; vp.translate[1] = 0.5f * height; vp.translate[2] = 0.5f; cso_set_viewport(cso, &vp); } cso_set_vertex_elements(cso, 3, st->velems_util_draw); cso_set_stream_outputs(st->cso_context, 0, NULL, NULL); /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0f - 1.0f; /* draw textured quad */ setup_bitmap_vertex_data(st, sv->texture->target != PIPE_TEXTURE_RECT, x, y, width, height, z, color, &vbuf, &offset); if (vbuf) { util_draw_vertex_buffer(pipe, st->cso_context, vbuf, cso_get_aux_vertex_buffer_slot(st->cso_context), offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 3); /* attribs/vert */ } /* restore state */ cso_restore_rasterizer(cso); cso_restore_fragment_samplers(cso); cso_restore_fragment_sampler_views(cso); cso_restore_viewport(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); cso_restore_tessctrl_shader(cso); cso_restore_tesseval_shader(cso); cso_restore_geometry_shader(cso); cso_restore_vertex_elements(cso); cso_restore_aux_vertex_buffer_slot(cso); cso_restore_stream_outputs(cso); pipe_resource_reference(&vbuf, NULL); /* We uploaded modified constants, need to invalidate them. */ st->dirty.mesa |= _NEW_PROGRAM_CONSTANTS; }
static void draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z, GLsizei width, GLsizei height, GLfloat zoomX, GLfloat zoomY, struct pipe_sampler_view **sv, int num_sampler_view, void *driver_vp, void *driver_fp, const GLfloat *color, GLboolean invertTex, GLboolean write_depth, GLboolean write_stencil) { struct st_context *st = st_context(ctx); struct pipe_context *pipe = st->pipe; struct cso_context *cso = st->cso_context; GLfloat x0, y0, x1, y1; GLsizei maxSize; boolean normalized = sv[0]->texture->target != PIPE_TEXTURE_RECT; /* limit checks */ /* XXX if DrawPixels image is larger than max texture size, break * it up into chunks. */ maxSize = 1 << (pipe->screen->get_param(pipe->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1); assert(width <= maxSize); assert(height <= maxSize); cso_save_rasterizer(cso); cso_save_viewport(cso); cso_save_samplers(cso); cso_save_fragment_sampler_views(cso); cso_save_fragment_shader(cso); cso_save_vertex_shader(cso); cso_save_vertex_elements(cso); cso_save_vertex_buffers(cso); if (write_stencil) { cso_save_depth_stencil_alpha(cso); cso_save_blend(cso); } /* rasterizer state: just scissor */ { struct pipe_rasterizer_state rasterizer; memset(&rasterizer, 0, sizeof(rasterizer)); rasterizer.clamp_fragment_color = ctx->Color._ClampFragmentColor; rasterizer.gl_rasterization_rules = 1; rasterizer.scissor = ctx->Scissor.Enabled; cso_set_rasterizer(cso, &rasterizer); } if (write_stencil) { /* Stencil writing bypasses the normal fragment pipeline to * disable color writing and set stencil test to always pass. */ struct pipe_depth_stencil_alpha_state dsa; struct pipe_blend_state blend; /* depth/stencil */ memset(&dsa, 0, sizeof(dsa)); dsa.stencil[0].enabled = 1; dsa.stencil[0].func = PIPE_FUNC_ALWAYS; dsa.stencil[0].writemask = ctx->Stencil.WriteMask[0] & 0xff; dsa.stencil[0].zpass_op = PIPE_STENCIL_OP_REPLACE; if (write_depth) { /* writing depth+stencil: depth test always passes */ dsa.depth.enabled = 1; dsa.depth.writemask = ctx->Depth.Mask; dsa.depth.func = PIPE_FUNC_ALWAYS; } cso_set_depth_stencil_alpha(cso, &dsa); /* blend (colormask) */ memset(&blend, 0, sizeof(blend)); cso_set_blend(cso, &blend); } /* fragment shader state: TEX lookup program */ cso_set_fragment_shader_handle(cso, driver_fp); /* vertex shader state: position + texcoord pass-through */ cso_set_vertex_shader_handle(cso, driver_vp); /* texture sampling state: */ { struct pipe_sampler_state sampler; memset(&sampler, 0, sizeof(sampler)); sampler.wrap_s = PIPE_TEX_WRAP_CLAMP; sampler.wrap_t = PIPE_TEX_WRAP_CLAMP; sampler.wrap_r = PIPE_TEX_WRAP_CLAMP; sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.normalized_coords = normalized; cso_single_sampler(cso, 0, &sampler); if (num_sampler_view > 1) { cso_single_sampler(cso, 1, &sampler); } cso_single_sampler_done(cso); } /* viewport state: viewport matching window dims */ { const float w = (float) ctx->DrawBuffer->Width; const float h = (float) ctx->DrawBuffer->Height; struct pipe_viewport_state vp; vp.scale[0] = 0.5f * w; vp.scale[1] = -0.5f * h; vp.scale[2] = 0.5f; vp.scale[3] = 1.0f; vp.translate[0] = 0.5f * w; vp.translate[1] = 0.5f * h; vp.translate[2] = 0.5f; vp.translate[3] = 0.0f; cso_set_viewport(cso, &vp); } cso_set_vertex_elements(cso, 3, st->velems_util_draw); /* texture state: */ cso_set_fragment_sampler_views(cso, num_sampler_view, sv); /* Compute Gallium window coords (y=0=top) with pixel zoom. * Recall that these coords are transformed by the current * vertex shader and viewport transformation. */ if (st_fb_orientation(ctx->DrawBuffer) == Y_0_BOTTOM) { y = ctx->DrawBuffer->Height - (int) (y + height * ctx->Pixel.ZoomY); invertTex = !invertTex; } x0 = (GLfloat) x; x1 = x + width * ctx->Pixel.ZoomX; y0 = (GLfloat) y; y1 = y + height * ctx->Pixel.ZoomY; /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */ z = z * 2.0 - 1.0; draw_quad(ctx, x0, y0, z, x1, y1, color, invertTex, normalized ? ((GLfloat) width / sv[0]->texture->width0) : (GLfloat)width, normalized ? ((GLfloat) height / sv[0]->texture->height0) : (GLfloat)height); /* restore state */ cso_restore_rasterizer(cso); cso_restore_viewport(cso); cso_restore_samplers(cso); cso_restore_fragment_sampler_views(cso); cso_restore_fragment_shader(cso); cso_restore_vertex_shader(cso); cso_restore_vertex_elements(cso); cso_restore_vertex_buffers(cso); if (write_stencil) { cso_restore_depth_stencil_alpha(cso); cso_restore_blend(cso); } }
/** * Prepare the renderer for image filtering. */ VGboolean renderer_filter_begin(struct renderer *renderer, struct pipe_resource *dst, VGboolean y0_top, VGbitfield channel_mask, const struct pipe_sampler_state **samplers, struct pipe_sampler_view **views, VGint num_samplers, void *fs, const void *const_buffer, VGint const_buffer_len) { struct pipe_surface *surf, surf_tmpl; assert(renderer->state == RENDERER_STATE_INIT); if (!fs) return VG_FALSE; if (!renderer_can_support(renderer, dst, PIPE_BIND_RENDER_TARGET)) return VG_FALSE; u_surface_default_template(&surf_tmpl, dst, PIPE_BIND_RENDER_TARGET); surf = renderer->pipe->create_surface(renderer->pipe, dst, &surf_tmpl); if (!surf) return VG_FALSE; cso_save_framebuffer(renderer->cso); cso_save_viewport(renderer->cso); cso_save_blend(renderer->cso); /* set the image as the target */ renderer_set_target(renderer, surf, NULL, y0_top); pipe_surface_reference(&surf, NULL); renderer_set_blend(renderer, channel_mask); if (num_samplers) { struct pipe_resource *tex; cso_save_samplers(renderer->cso); cso_save_fragment_sampler_views(renderer->cso); cso_save_fragment_shader(renderer->cso); cso_save_vertex_shader(renderer->cso); renderer_set_custom_fs(renderer, fs, samplers, views, num_samplers, const_buffer, const_buffer_len); renderer_set_vs(renderer, RENDERER_VS_TEXTURE); tex = views[0]->texture; renderer->u.filter.tex_width = tex->width0; renderer->u.filter.tex_height = tex->height0; renderer->u.filter.use_sampler = VG_TRUE; } else { cso_save_fragment_shader(renderer->cso); renderer_set_custom_fs(renderer, fs, NULL, NULL, 0, const_buffer, const_buffer_len); renderer->u.filter.use_sampler = VG_FALSE; } renderer_set_mvp(renderer, NULL); renderer->state = RENDERER_STATE_FILTER; return VG_TRUE; }
/** * Copy pixel block from src texture to dst surface. * The sampler view's first_level field indicates the source * mipmap level to use. * XXX need some control over blitting Z and/or stencil. */ void util_blit_pixels_tex(struct blit_state *ctx, struct pipe_sampler_view *src_sampler_view, int srcX0, int srcY0, int srcX1, int srcY1, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter) { boolean normalized = src_sampler_view->texture->target != PIPE_TEXTURE_RECT; struct pipe_framebuffer_state fb; float s0, t0, s1, t1; unsigned offset; struct pipe_resource *tex = src_sampler_view->texture; assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(tex); assert(tex->width0 != 0); assert(tex->height0 != 0); s0 = srcX0; s1 = srcX1; t0 = srcY0; t1 = srcY1; if(normalized) { /* normalize according to the mipmap level's size */ int level = src_sampler_view->u.tex.first_level; float w = (float) u_minify(tex->width0, level); float h = (float) u_minify(tex->height0, level); s0 /= w; s1 /= w; t0 /= h; t1 /= h; } assert(ctx->pipe->screen->is_format_supported(ctx->pipe->screen, dst->format, PIPE_TEXTURE_2D, dst->texture->nr_samples, PIPE_BIND_RENDER_TARGET)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_samplers(ctx->cso); cso_save_fragment_sampler_views(ctx->cso); cso_save_stream_outputs(ctx->cso); cso_save_viewport(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_vertex_buffers(ctx->cso); /* set misc state we care about */ cso_set_blend(ctx->cso, &ctx->blend_write_color); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, 0); /* sampler */ ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; cso_single_sampler(ctx->cso, 0, &ctx->sampler); cso_single_sampler_done(ctx->cso); /* viewport */ ctx->viewport.scale[0] = 0.5f * dst->width; ctx->viewport.scale[1] = 0.5f * dst->height; ctx->viewport.scale[2] = 0.5f; ctx->viewport.scale[3] = 1.0f; ctx->viewport.translate[0] = 0.5f * dst->width; ctx->viewport.translate[1] = 0.5f * dst->height; ctx->viewport.translate[2] = 0.5f; ctx->viewport.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &ctx->viewport); /* texture */ cso_set_fragment_sampler_views(ctx->cso, 1, &src_sampler_view); /* shaders */ set_fragment_shader(ctx, TGSI_WRITEMASK_XYZW, src_sampler_view->texture->target); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst->width; fb.height = dst->height; fb.nr_cbufs = 1; fb.cbufs[0] = dst; cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ offset = setup_vertex_data_tex(ctx, (float) dstX0 / dst->width * 2.0f - 1.0f, (float) dstY0 / dst->height * 2.0f - 1.0f, (float) dstX1 / dst->width * 2.0f - 1.0f, (float) dstY1 / dst->height * 2.0f - 1.0f, s0, t0, s1, t1, z); util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_samplers(ctx->cso); cso_restore_fragment_sampler_views(ctx->cso); cso_restore_viewport(ctx->cso); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_vertex_buffers(ctx->cso); cso_restore_stream_outputs(ctx->cso); }
/** * Copy pixel block from src surface to dst surface. * Overlapping regions are acceptable. * Flipping and stretching are supported. * \param filter one of PIPE_TEX_MIPFILTER_NEAREST/LINEAR * \param writemask controls which channels in the dest surface are sourced * from the src surface. Disabled channels are sourced * from (0,0,0,1). */ void util_blit_pixels(struct blit_state *ctx, struct pipe_resource *src_tex, unsigned src_level, int srcX0, int srcY0, int srcX1, int srcY1, int srcZ0, struct pipe_surface *dst, int dstX0, int dstY0, int dstX1, int dstY1, float z, uint filter, uint writemask, uint zs_writemask) { struct pipe_context *pipe = ctx->pipe; struct pipe_screen *screen = pipe->screen; enum pipe_format src_format, dst_format; struct pipe_sampler_view *sampler_view = NULL; struct pipe_sampler_view sv_templ; struct pipe_surface *dst_surface; struct pipe_framebuffer_state fb; const int srcW = abs(srcX1 - srcX0); const int srcH = abs(srcY1 - srcY0); unsigned offset; boolean overlap; float s0, t0, s1, t1; boolean normalized; boolean is_stencil, is_depth, blit_depth, blit_stencil; const struct util_format_description *src_desc = util_format_description(src_tex->format); assert(filter == PIPE_TEX_MIPFILTER_NEAREST || filter == PIPE_TEX_MIPFILTER_LINEAR); assert(src_level <= src_tex->last_level); /* do the regions overlap? */ overlap = src_tex == dst->texture && dst->u.tex.level == src_level && dst->u.tex.first_layer == srcZ0 && regions_overlap(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1); src_format = util_format_linear(src_tex->format); dst_format = util_format_linear(dst->format); /* See whether we will blit depth or stencil. */ is_depth = util_format_has_depth(src_desc); is_stencil = util_format_has_stencil(src_desc); blit_depth = is_depth && (zs_writemask & BLIT_WRITEMASK_Z); blit_stencil = is_stencil && (zs_writemask & BLIT_WRITEMASK_STENCIL); assert((writemask && !zs_writemask && !is_depth && !is_stencil) || (!writemask && (blit_depth || blit_stencil))); /* * Check for simple case: no format conversion, no flipping, no stretching, * no overlapping. * Filter mode should not matter since there's no stretching. */ if (formats_compatible(src_format, dst_format) && is_stencil == blit_stencil && is_depth == blit_depth && srcX0 < srcX1 && dstX0 < dstX1 && srcY0 < srcY1 && dstY0 < dstY1 && (dstX1 - dstX0) == (srcX1 - srcX0) && (dstY1 - dstY0) == (srcY1 - srcY0) && !overlap) { struct pipe_box src_box; src_box.x = srcX0; src_box.y = srcY0; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; pipe->resource_copy_region(pipe, dst->texture, dst->u.tex.level, dstX0, dstY0, dst->u.tex.first_layer,/* dest */ src_tex, src_level, &src_box); return; } /* It's a mistake to call this function with a stencil format and * without shader stencil export. We don't do software fallbacks here. * Ignore stencil and only copy depth. */ if (blit_stencil && !ctx->has_stencil_export) { blit_stencil = FALSE; if (!blit_depth) return; } if (dst_format == dst->format) { dst_surface = dst; } else { struct pipe_surface templ = *dst; templ.format = dst_format; dst_surface = pipe->create_surface(pipe, dst->texture, &templ); } /* Create a temporary texture when src and dest alias. */ if (src_tex == dst_surface->texture && dst_surface->u.tex.level == src_level && dst_surface->u.tex.first_layer == srcZ0) { /* Make a temporary texture which contains a copy of the source pixels. * Then we'll sample from the temporary texture. */ struct pipe_resource texTemp; struct pipe_resource *tex; struct pipe_sampler_view sv_templ; struct pipe_box src_box; const int srcLeft = MIN2(srcX0, srcX1); const int srcTop = MIN2(srcY0, srcY1); if (srcLeft != srcX0) { /* left-right flip */ int tmp = dstX0; dstX0 = dstX1; dstX1 = tmp; } if (srcTop != srcY0) { /* up-down flip */ int tmp = dstY0; dstY0 = dstY1; dstY1 = tmp; } /* create temp texture */ memset(&texTemp, 0, sizeof(texTemp)); texTemp.target = ctx->internal_target; texTemp.format = src_format; texTemp.last_level = 0; texTemp.width0 = srcW; texTemp.height0 = srcH; texTemp.depth0 = 1; texTemp.array_size = 1; texTemp.bind = PIPE_BIND_SAMPLER_VIEW; tex = screen->resource_create(screen, &texTemp); if (!tex) return; src_box.x = srcLeft; src_box.y = srcTop; src_box.z = srcZ0; src_box.width = srcW; src_box.height = srcH; src_box.depth = 1; /* load temp texture */ pipe->resource_copy_region(pipe, tex, 0, 0, 0, 0, /* dest */ src_tex, src_level, &src_box); normalized = tex->target != PIPE_TEXTURE_RECT; if(normalized) { s0 = 0.0f; s1 = 1.0f; t0 = 0.0f; t1 = 1.0f; } else { s0 = 0; s1 = srcW; t0 = 0; t1 = srcH; } u_sampler_view_default_template(&sv_templ, tex, tex->format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(tex->format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, tex, &sv_templ); if (!sampler_view) { pipe_resource_reference(&tex, NULL); return; } pipe_resource_reference(&tex, NULL); } else { /* Directly sample from the source resource/texture */ u_sampler_view_default_template(&sv_templ, src_tex, src_format); if (!blit_depth && blit_stencil) { /* set a stencil-only format, e.g. Z24S8 --> X24S8 */ sv_templ.format = util_format_stencil_only(src_format); assert(sv_templ.format != PIPE_FORMAT_NONE); } sampler_view = pipe->create_sampler_view(pipe, src_tex, &sv_templ); if (!sampler_view) { return; } s0 = srcX0; s1 = srcX1; t0 = srcY0; t1 = srcY1; normalized = sampler_view->texture->target != PIPE_TEXTURE_RECT; if(normalized) { s0 /= (float)(u_minify(sampler_view->texture->width0, src_level)); s1 /= (float)(u_minify(sampler_view->texture->width0, src_level)); t0 /= (float)(u_minify(sampler_view->texture->height0, src_level)); t1 /= (float)(u_minify(sampler_view->texture->height0, src_level)); } } assert(screen->is_format_supported(screen, sampler_view->format, ctx->internal_target, sampler_view->texture->nr_samples, PIPE_BIND_SAMPLER_VIEW)); assert(screen->is_format_supported(screen, dst_format, ctx->internal_target, dst_surface->texture->nr_samples, is_depth || is_stencil ? PIPE_BIND_DEPTH_STENCIL : PIPE_BIND_RENDER_TARGET)); /* save state (restored below) */ cso_save_blend(ctx->cso); cso_save_depth_stencil_alpha(ctx->cso); cso_save_rasterizer(ctx->cso); cso_save_samplers(ctx->cso); cso_save_fragment_sampler_views(ctx->cso); cso_save_stream_outputs(ctx->cso); cso_save_viewport(ctx->cso); cso_save_framebuffer(ctx->cso); cso_save_fragment_shader(ctx->cso); cso_save_vertex_shader(ctx->cso); cso_save_geometry_shader(ctx->cso); cso_save_vertex_elements(ctx->cso); cso_save_vertex_buffers(ctx->cso); /* set misc state we care about */ if (writemask) cso_set_blend(ctx->cso, &ctx->blend_write_color); else cso_set_blend(ctx->cso, &ctx->blend_keep_color); cso_set_rasterizer(ctx->cso, &ctx->rasterizer); cso_set_vertex_elements(ctx->cso, 2, ctx->velem); cso_set_stream_outputs(ctx->cso, 0, NULL, 0); /* default sampler state */ ctx->sampler.normalized_coords = normalized; ctx->sampler.min_img_filter = filter; ctx->sampler.mag_img_filter = filter; ctx->sampler.min_lod = src_level; ctx->sampler.max_lod = src_level; /* Depth stencil state, fragment shader and sampler setup depending on what * we blit. */ if (blit_depth && blit_stencil) { cso_single_sampler(ctx->cso, 0, &ctx->sampler); /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, 1, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depthstencil); set_depthstencil_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_depth) { cso_single_sampler(ctx->cso, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_depth); set_depth_fragment_shader(ctx, sampler_view->texture->target); } else if (blit_stencil) { /* don't filter stencil */ ctx->sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; ctx->sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; cso_single_sampler(ctx->cso, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_write_stencil); set_stencil_fragment_shader(ctx, sampler_view->texture->target); } else { /* color */ cso_single_sampler(ctx->cso, 0, &ctx->sampler); cso_set_depth_stencil_alpha(ctx->cso, &ctx->dsa_keep_depthstencil); set_fragment_shader(ctx, writemask, sampler_view->texture->target); } cso_single_sampler_done(ctx->cso); /* textures */ if (blit_depth && blit_stencil) { /* Setup two samplers, one for depth and the other one for stencil. */ struct pipe_sampler_view templ; struct pipe_sampler_view *views[2]; templ = *sampler_view; templ.format = util_format_stencil_only(templ.format); assert(templ.format != PIPE_FORMAT_NONE); views[0] = sampler_view; views[1] = pipe->create_sampler_view(pipe, views[0]->texture, &templ); cso_set_fragment_sampler_views(ctx->cso, 2, views); pipe_sampler_view_reference(&views[1], NULL); } else { cso_set_fragment_sampler_views(ctx->cso, 1, &sampler_view); } /* viewport */ ctx->viewport.scale[0] = 0.5f * dst_surface->width; ctx->viewport.scale[1] = 0.5f * dst_surface->height; ctx->viewport.scale[2] = 0.5f; ctx->viewport.scale[3] = 1.0f; ctx->viewport.translate[0] = 0.5f * dst_surface->width; ctx->viewport.translate[1] = 0.5f * dst_surface->height; ctx->viewport.translate[2] = 0.5f; ctx->viewport.translate[3] = 0.0f; cso_set_viewport(ctx->cso, &ctx->viewport); set_vertex_shader(ctx); cso_set_geometry_shader_handle(ctx->cso, NULL); /* drawing dest */ memset(&fb, 0, sizeof(fb)); fb.width = dst_surface->width; fb.height = dst_surface->height; if (blit_depth || blit_stencil) { fb.zsbuf = dst_surface; } else { fb.nr_cbufs = 1; fb.cbufs[0] = dst_surface; } cso_set_framebuffer(ctx->cso, &fb); /* draw quad */ offset = setup_vertex_data_tex(ctx, (float) dstX0 / dst_surface->width * 2.0f - 1.0f, (float) dstY0 / dst_surface->height * 2.0f - 1.0f, (float) dstX1 / dst_surface->width * 2.0f - 1.0f, (float) dstY1 / dst_surface->height * 2.0f - 1.0f, s0, t0, s1, t1, z); if (ctx->vbuf) { util_draw_vertex_buffer(ctx->pipe, ctx->cso, ctx->vbuf, offset, PIPE_PRIM_TRIANGLE_FAN, 4, /* verts */ 2); /* attribs/vert */ } /* restore state we changed */ cso_restore_blend(ctx->cso); cso_restore_depth_stencil_alpha(ctx->cso); cso_restore_rasterizer(ctx->cso); cso_restore_samplers(ctx->cso); cso_restore_fragment_sampler_views(ctx->cso); cso_restore_viewport(ctx->cso); cso_restore_framebuffer(ctx->cso); cso_restore_fragment_shader(ctx->cso); cso_restore_vertex_shader(ctx->cso); cso_restore_geometry_shader(ctx->cso); cso_restore_vertex_elements(ctx->cso); cso_restore_vertex_buffers(ctx->cso); cso_restore_stream_outputs(ctx->cso); pipe_sampler_view_reference(&sampler_view, NULL); if (dst_surface != dst) pipe_surface_reference(&dst_surface, NULL); }