/**************************************************************************
- *
+ *
* Copyright 2007 VMware, Inc.
* All Rights Reserved.
- *
+ *
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
- *
+ *
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
+ *
**************************************************************************/
/*
* Brian Paul
*/
-#include "main/imports.h"
+#include "main/errors.h"
+
#include "main/image.h"
#include "main/bufferobj.h"
#include "main/blit.h"
#include "main/pack.h"
#include "main/pbo.h"
#include "main/readpix.h"
+#include "main/state.h"
#include "main/texformat.h"
#include "main/teximage.h"
#include "main/texstore.h"
#include "st_sampler_view.h"
#include "st_scissor.h"
#include "st_texture.h"
+#include "st_util.h"
+#include "st_nir.h"
#include "pipe/p_context.h"
#include "pipe/p_defines.h"
#include "tgsi/tgsi_ureg.h"
-#include "util/u_format.h"
+#include "util/format/u_format.h"
#include "util/u_inlines.h"
#include "util/u_math.h"
+#include "util/u_simple_shaders.h"
#include "util/u_tile.h"
#include "cso_cache/cso_context.h"
+#include "compiler/nir/nir_builder.h"
/**
* We have a simple glDrawPixels cache to try to optimize the case where the
*/
#define USE_DRAWPIXELS_CACHE 1
+static nir_ssa_def *
+sample_via_nir(nir_builder *b, nir_variable *texcoord,
+ const char *name, int sampler, enum glsl_base_type base_type,
+ nir_alu_type alu_type)
+{
+ const struct glsl_type *sampler2D =
+ glsl_sampler_type(GLSL_SAMPLER_DIM_2D, false, false, base_type);
+
+ nir_variable *var =
+ nir_variable_create(b->shader, nir_var_uniform, sampler2D, name);
+ var->data.binding = sampler;
+ var->data.explicit_binding = true;
+
+ nir_deref_instr *deref = nir_build_deref_var(b, var);
+
+ nir_tex_instr *tex = nir_tex_instr_create(b->shader, 3);
+ tex->op = nir_texop_tex;
+ tex->sampler_dim = GLSL_SAMPLER_DIM_2D;
+ tex->coord_components = 2;
+ tex->dest_type = alu_type;
+ tex->src[0].src_type = nir_tex_src_texture_deref;
+ tex->src[0].src = nir_src_for_ssa(&deref->dest.ssa);
+ tex->src[1].src_type = nir_tex_src_sampler_deref;
+ tex->src[1].src = nir_src_for_ssa(&deref->dest.ssa);
+ tex->src[2].src_type = nir_tex_src_coord;
+ tex->src[2].src =
+ nir_src_for_ssa(nir_channels(b, nir_load_var(b, texcoord),
+ (1 << tex->coord_components) - 1));
+
+ nir_ssa_dest_init(&tex->instr, &tex->dest, 4, 32, NULL);
+ nir_builder_instr_insert(b, &tex->instr);
+ return nir_channel(b, &tex->dest.ssa, 0);
+}
+
+static void *
+make_drawpix_z_stencil_program_nir(struct st_context *st,
+ bool write_depth,
+ bool write_stencil)
+{
+ struct nir_builder b;
+ const nir_shader_compiler_options *options =
+ st->ctx->Const.ShaderCompilerOptions[MESA_SHADER_FRAGMENT].NirOptions;
+
+ nir_builder_init_simple_shader(&b, NULL, MESA_SHADER_FRAGMENT, options);
+
+ nir_variable *texcoord =
+ nir_variable_create(b.shader, nir_var_shader_in, glsl_vec_type(2),
+ "texcoord");
+ texcoord->data.location = VARYING_SLOT_TEX0;
+
+ if (write_depth) {
+ nir_variable *out =
+ nir_variable_create(b.shader, nir_var_shader_out, glsl_float_type(),
+ "gl_FragDepth");
+ out->data.location = FRAG_RESULT_DEPTH;
+ nir_ssa_def *depth = sample_via_nir(&b, texcoord, "depth", 0,
+ GLSL_TYPE_FLOAT, nir_type_float);
+ nir_store_var(&b, out, depth, 0x1);
+
+ /* Also copy color */
+ nir_variable *color_in =
+ nir_variable_create(b.shader, nir_var_shader_in, glsl_vec_type(4),
+ "v_color");
+ color_in->data.location = VARYING_SLOT_COL0;
+
+ nir_variable *color_out =
+ nir_variable_create(b.shader, nir_var_shader_out, glsl_vec_type(4),
+ "gl_FragColor");
+ color_out->data.location = FRAG_RESULT_COLOR;
+ nir_copy_var(&b, color_out, color_in);
+ }
+
+ if (write_stencil) {
+ nir_variable *out =
+ nir_variable_create(b.shader, nir_var_shader_out, glsl_uint_type(),
+ "gl_FragStencilRefARB");
+ out->data.location = FRAG_RESULT_STENCIL;
+ nir_ssa_def *stencil = sample_via_nir(&b, texcoord, "stencil", 1,
+ GLSL_TYPE_UINT, nir_type_uint);
+ nir_store_var(&b, out, stencil, 0x1);
+ }
+
+ char name[14];
+ snprintf(name, 14, "drawpixels %s%s",
+ write_depth ? "Z" : "", write_stencil ? "S" : "");
+
+ return st_nir_finish_builtin_shader(st, b.shader, name);
+}
-/**
- * Create fragment program that does a TEX() instruction to get a Z and/or
- * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL.
- * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX).
- * Pass fragment color through as-is.
- *
- * \return CSO of the fragment shader.
- */
static void *
-get_drawpix_z_stencil_program(struct st_context *st,
- GLboolean write_depth,
- GLboolean write_stencil)
+make_drawpix_z_stencil_program_tgsi(struct st_context *st,
+ bool write_depth,
+ bool write_stencil)
{
struct ureg_program *ureg;
struct ureg_src depth_sampler, stencil_sampler;
struct ureg_src texcoord, color;
struct ureg_dst out_color, out_depth, out_stencil;
- const GLuint shaderIndex = write_depth * 2 + write_stencil;
- void *cso;
-
- assert(shaderIndex < ARRAY_SIZE(st->drawpix.zs_shaders));
-
- if (st->drawpix.zs_shaders[shaderIndex]) {
- /* already have the proper shader */
- return st->drawpix.zs_shaders[shaderIndex];
- }
ureg = ureg_create(PIPE_SHADER_FRAGMENT);
if (ureg == NULL)
TGSI_TEXTURE_2D, texcoord, stencil_sampler);
ureg_END(ureg);
- cso = ureg_create_shader_and_destroy(ureg, st->pipe);
+ return ureg_create_shader_and_destroy(ureg, st->pipe);
+}
+
+
+/**
+ * Create fragment program that does a TEX() instruction to get a Z and/or
+ * stencil value value, then writes to FRAG_RESULT_DEPTH/FRAG_RESULT_STENCIL.
+ * Used for glDrawPixels(GL_DEPTH_COMPONENT / GL_STENCIL_INDEX).
+ * Pass fragment color through as-is.
+ *
+ * \return CSO of the fragment shader.
+ */
+static void *
+get_drawpix_z_stencil_program(struct st_context *st,
+ bool write_depth,
+ bool write_stencil)
+{
+ struct pipe_screen *pscreen = st->pipe->screen;
+ const GLuint shaderIndex = write_depth * 2 + write_stencil;
+ void *cso;
+
+ assert(shaderIndex < ARRAY_SIZE(st->drawpix.zs_shaders));
+
+ if (st->drawpix.zs_shaders[shaderIndex]) {
+ /* already have the proper shader */
+ return st->drawpix.zs_shaders[shaderIndex];
+ }
+
+ enum pipe_shader_ir preferred_ir =
+ pscreen->get_shader_param(pscreen, PIPE_SHADER_FRAGMENT,
+ PIPE_SHADER_CAP_PREFERRED_IR);
+
+ if (preferred_ir == PIPE_SHADER_IR_NIR)
+ cso = make_drawpix_z_stencil_program_nir(st, write_depth, write_stencil);
+ else
+ cso = make_drawpix_z_stencil_program_tgsi(st, write_depth, write_stencil);
/* save the new shader */
st->drawpix.zs_shaders[shaderIndex] = cso;
/**
* Create a simple vertex shader that just passes through the
- * vertex position and texcoord (and optionally, color).
+ * vertex position, texcoord, and color.
*/
-static void *
-make_passthrough_vertex_shader(struct st_context *st,
- GLboolean passColor)
+void
+st_make_passthrough_vertex_shader(struct st_context *st)
{
- const unsigned texcoord_semantic = st->needs_texcoord_semantic ?
- TGSI_SEMANTIC_TEXCOORD : TGSI_SEMANTIC_GENERIC;
-
- if (!st->drawpix.vert_shaders[passColor]) {
- struct ureg_program *ureg = ureg_create( PIPE_SHADER_VERTEX );
+ struct pipe_context *pipe = st->pipe;
+ struct pipe_screen *screen = pipe->screen;
- if (ureg == NULL)
- return NULL;
+ if (st->passthrough_vs)
+ return;
- /* MOV result.pos, vertex.pos; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, TGSI_SEMANTIC_POSITION, 0 ),
- ureg_DECL_vs_input( ureg, 0 ));
+ enum pipe_shader_ir preferred_ir =
+ screen->get_shader_param(screen, PIPE_SHADER_VERTEX,
+ PIPE_SHADER_CAP_PREFERRED_IR);
- if (passColor) {
- /* MOV result.color0, vertex.attr[1]; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, TGSI_SEMANTIC_COLOR, 0 ),
- ureg_DECL_vs_input( ureg, 1 ));
- }
+ if (preferred_ir == PIPE_SHADER_IR_NIR) {
+ unsigned inputs[] =
+ { VERT_ATTRIB_POS, VERT_ATTRIB_COLOR0, VERT_ATTRIB_GENERIC0 };
+ unsigned outputs[] =
+ { VARYING_SLOT_POS, VARYING_SLOT_COL0, VARYING_SLOT_TEX0 };
- /* MOV result.texcoord0, vertex.attr[2]; */
- ureg_MOV(ureg,
- ureg_DECL_output( ureg, texcoord_semantic, 0 ),
- ureg_DECL_vs_input( ureg, 2 ));
-
- ureg_END( ureg );
-
- st->drawpix.vert_shaders[passColor] =
- ureg_create_shader_and_destroy( ureg, st->pipe );
+ st->passthrough_vs =
+ st_nir_make_passthrough_shader(st, "drawpixels VS",
+ MESA_SHADER_VERTEX, 3,
+ inputs, outputs, NULL, 0);
+ } else {
+ const enum tgsi_semantic semantic_names[] = {
+ TGSI_SEMANTIC_POSITION,
+ TGSI_SEMANTIC_COLOR,
+ st->needs_texcoord_semantic ? TGSI_SEMANTIC_TEXCOORD :
+ TGSI_SEMANTIC_GENERIC
+ };
+ const uint semantic_indexes[] = { 0, 0, 0 };
+
+ st->passthrough_vs =
+ util_make_vertex_passthrough_shader(st->pipe, 3, semantic_names,
+ semantic_indexes, false);
}
-
- return st->drawpix.vert_shaders[passColor];
}
}
+/**
+ * Search the cache for an image which matches the given parameters.
+ * \return pipe_resource pointer if found, NULL if not found.
+ */
+static struct pipe_resource *
+search_drawpixels_cache(struct st_context *st,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ const void *pixels)
+{
+ struct pipe_resource *pt = NULL;
+ const GLint bpp = _mesa_bytes_per_pixel(format, type);
+ unsigned i;
+
+ if ((unpack->RowLength != 0 && unpack->RowLength != width) ||
+ unpack->SkipPixels != 0 ||
+ unpack->SkipRows != 0 ||
+ unpack->SwapBytes ||
+ unpack->BufferObj) {
+ /* we don't allow non-default pixel unpacking values */
+ return NULL;
+ }
+
+ /* Search cache entries for a match */
+ for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) {
+ struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i];
+
+ if (width == entry->width &&
+ height == entry->height &&
+ format == entry->format &&
+ type == entry->type &&
+ pixels == entry->user_pointer &&
+ entry->image) {
+ assert(entry->texture);
+
+ /* check if the pixel data is the same */
+ if (memcmp(pixels, entry->image, width * height * bpp) == 0) {
+ /* Success - found a cache match */
+ pipe_resource_reference(&pt, entry->texture);
+ /* refcount of returned texture should be at least two here. One
+ * reference for the cache to hold on to, one for the caller (which
+ * it will release), and possibly more held by the driver.
+ */
+ assert(pt->reference.count >= 2);
+
+ /* update the age of this entry */
+ entry->age = ++st->drawpix_cache.age;
+
+ return pt;
+ }
+ }
+ }
+
+ /* no cache match found */
+ return NULL;
+}
+
+
+/**
+ * Find the oldest entry in the glDrawPixels cache. We'll replace this
+ * one when we need to store a new image.
+ */
+static struct drawpix_cache_entry *
+find_oldest_drawpixels_cache_entry(struct st_context *st)
+{
+ unsigned oldest_age = ~0u, oldest_index = ~0u;
+ unsigned i;
+
+ /* Find entry with oldest (lowest) age */
+ for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) {
+ const struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i];
+ if (entry->age < oldest_age) {
+ oldest_age = entry->age;
+ oldest_index = i;
+ }
+ }
+
+ assert(oldest_index != ~0u);
+
+ return &st->drawpix_cache.entries[oldest_index];
+}
+
+
+/**
+ * Try to save the given glDrawPixels image in the cache.
+ */
+static void
+cache_drawpixels_image(struct st_context *st,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type,
+ const struct gl_pixelstore_attrib *unpack,
+ const void *pixels,
+ struct pipe_resource *pt)
+{
+ if ((unpack->RowLength == 0 || unpack->RowLength == width) &&
+ unpack->SkipPixels == 0 &&
+ unpack->SkipRows == 0) {
+ const GLint bpp = _mesa_bytes_per_pixel(format, type);
+ struct drawpix_cache_entry *entry =
+ find_oldest_drawpixels_cache_entry(st);
+ assert(entry);
+ entry->width = width;
+ entry->height = height;
+ entry->format = format;
+ entry->type = type;
+ entry->user_pointer = pixels;
+ free(entry->image);
+ entry->image = malloc(width * height * bpp);
+ if (entry->image) {
+ memcpy(entry->image, pixels, width * height * bpp);
+ pipe_resource_reference(&entry->texture, pt);
+ entry->age = ++st->drawpix_cache.age;
+ }
+ else {
+ /* out of memory, free/disable cached texture */
+ entry->width = 0;
+ entry->height = 0;
+ pipe_resource_reference(&entry->texture, NULL);
+ }
+ }
+}
+
+
/**
* Make texture containing an image for glDrawPixels image.
* If 'pixels' is NULL, leave the texture image data undefined.
GLenum baseInternalFormat;
#if USE_DRAWPIXELS_CACHE
- const GLint bpp = _mesa_bytes_per_pixel(format, type);
-
- /* Check if the glDrawPixels() parameters and state matches the cache */
- if (width == st->drawpix_cache.width &&
- height == st->drawpix_cache.height &&
- format == st->drawpix_cache.format &&
- type == st->drawpix_cache.type &&
- pixels == st->drawpix_cache.user_pointer &&
- !_mesa_is_bufferobj(unpack->BufferObj) &&
- (unpack->RowLength == 0 || unpack->RowLength == width) &&
- unpack->SkipPixels == 0 &&
- unpack->SkipRows == 0 &&
- unpack->SwapBytes == GL_FALSE &&
- st->drawpix_cache.image) {
- assert(st->drawpix_cache.texture);
-
- /* check if the pixel data is the same */
- if (memcmp(pixels, st->drawpix_cache.image, width * height * bpp) == 0) {
- /* OK, re-use the cached texture */
- pipe_resource_reference(&pt, st->drawpix_cache.texture);
- /* refcount of returned texture should be at least two here. One
- * reference for the cache to hold on to, one for the caller (which
- * it will release), and possibly more held by the driver.
- */
- assert(pt->reference.count >= 2);
- return pt;
- }
- }
-
- /* discard the cached image and texture (if there is one) */
- st->drawpix_cache.width = 0;
- st->drawpix_cache.height = 0;
- st->drawpix_cache.user_pointer = NULL;
- if (st->drawpix_cache.image) {
- free(st->drawpix_cache.image);
- st->drawpix_cache.image = NULL;
+ pt = search_drawpixels_cache(st, width, height, format, type,
+ unpack, pixels);
+ if (pt) {
+ return pt;
}
- pipe_resource_reference(&st->drawpix_cache.texture, NULL);
#endif
/* Choose a pixel format for the temp texture which will hold the
GLenum intFormat = internal_format(ctx, format, type);
pipeFormat = st_choose_format(st, intFormat, format, type,
- st->internal_target, 0,
- PIPE_BIND_SAMPLER_VIEW, FALSE);
+ st->internal_target, 0, 0,
+ PIPE_BIND_SAMPLER_VIEW,
+ false, false);
assert(pipeFormat != PIPE_FORMAT_NONE);
}
{
struct pipe_transfer *transfer;
- GLboolean success;
GLubyte *dest;
const GLbitfield imageTransferStateSave = ctx->_ImageTransferState;
dest = pipe_transfer_map(pipe, pt, 0, 0,
PIPE_TRANSFER_WRITE, 0, 0,
width, height, &transfer);
-
+ if (!dest) {
+ pipe_resource_reference(&pt, NULL);
+ _mesa_unmap_pbo_source(ctx, unpack);
+ return NULL;
+ }
/* Put image into texture transfer.
* Note that the image is actually going to be upside down in
format, type, /* src format/type */
pixels, /* data source */
unpack);
- success = GL_TRUE;
}
else {
+ ASSERTED bool success;
success = _mesa_texstore(ctx, 2, /* dims */
baseInternalFormat, /* baseInternalFormat */
mformat, /* mesa_format */
format, type, /* src format/type */
pixels, /* data source */
unpack);
+
+ assert(success);
}
/* unmap */
pipe_transfer_unmap(pipe, transfer);
- assert(success);
-
/* restore */
ctx->_ImageTransferState = imageTransferStateSave;
}
- _mesa_unmap_pbo_source(ctx, unpack);
-
#if USE_DRAWPIXELS_CACHE
- /* Save the glDrawPixels parameter and image in the cache */
- if ((unpack->RowLength == 0 || unpack->RowLength == width) &&
- unpack->SkipPixels == 0 &&
- unpack->SkipRows == 0) {
- st->drawpix_cache.width = width;
- st->drawpix_cache.height = height;
- st->drawpix_cache.format = format;
- st->drawpix_cache.type = type;
- st->drawpix_cache.user_pointer = pixels;
- assert(!st->drawpix_cache.image);
- st->drawpix_cache.image = malloc(width * height * bpp);
- if (st->drawpix_cache.image) {
- memcpy(st->drawpix_cache.image, pixels, width * height * bpp);
- pipe_resource_reference(&st->drawpix_cache.texture, pt);
- }
- else {
- /* out of memory, free/disable cached texture */
- st->drawpix_cache.width = 0;
- st->drawpix_cache.height = 0;
- pipe_resource_reference(&st->drawpix_cache.texture, NULL);
- }
- }
+ cache_drawpixels_image(st, width, height, format, type, unpack, pixels, pt);
#endif
+ _mesa_unmap_pbo_source(ctx, unpack);
+
return pt;
}
const unsigned fb_width = _mesa_geometric_width(ctx->DrawBuffer);
const unsigned fb_height = _mesa_geometric_height(ctx->DrawBuffer);
GLfloat x0, y0, x1, y1;
- GLsizei maxSize;
+ ASSERTED GLsizei maxSize;
boolean normalized = sv[0]->texture->target == PIPE_TEXTURE_2D;
unsigned cso_state_mask;
/* 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);
+ maxSize = pipe->screen->get_param(pipe->screen,
+ PIPE_CAP_MAX_TEXTURE_2D_SIZE);
assert(width <= maxSize);
assert(height <= maxSize);
ctx->Color._ClampFragmentColor;
rasterizer.half_pixel_center = 1;
rasterizer.bottom_edge_rule = 1;
- rasterizer.depth_clip = !ctx->Transform.DepthClamp;
+ rasterizer.depth_clip_near = st->clamp_frag_depth_in_shader ||
+ !ctx->Transform.DepthClampNear;
+ rasterizer.depth_clip_far = st->clamp_frag_depth_in_shader ||
+ !ctx->Transform.DepthClampFar;
rasterizer.scissor = ctx->Scissor.EnableFlags;
cso_set_rasterizer(cso, &rasterizer);
}
const struct pipe_sampler_state *samplers[PIPE_MAX_SAMPLERS];
uint num = MAX3(fpv->drawpix_sampler + 1,
fpv->pixelmap_sampler + 1,
- st->state.num_samplers[PIPE_SHADER_FRAGMENT]);
+ st->state.num_frag_samplers);
uint i;
- for (i = 0; i < st->state.num_samplers[PIPE_SHADER_FRAGMENT]; i++)
- samplers[i] = &st->state.samplers[PIPE_SHADER_FRAGMENT][i];
+ for (i = 0; i < st->state.num_frag_samplers; i++)
+ samplers[i] = &st->state.frag_samplers[i];
samplers[fpv->drawpix_sampler] = &sampler;
if (sv[1])
fpv->pixelmap_sampler + 1,
st->state.num_sampler_views[PIPE_SHADER_FRAGMENT]);
- memcpy(sampler_views, st->state.sampler_views[PIPE_SHADER_FRAGMENT],
+ memcpy(sampler_views, st->state.frag_sampler_views,
sizeof(sampler_views));
sampler_views[fpv->drawpix_sampler] = sv[0];
/* viewport state: viewport matching window dims */
cso_set_viewport_dims(cso, fb_width, fb_height, TRUE);
- cso_set_vertex_elements(cso, 3, st->util_velems);
+ st->util_velems.count = 3;
+ cso_set_vertex_elements(cso, &st->util_velems);
cso_set_stream_outputs(cso, 0, NULL, NULL);
/* Compute Gallium window coords (y=0=top) with pixel zoom.
y = ctx->DrawBuffer->Height - y - height;
}
- if (format == GL_STENCIL_INDEX &&
+ if (format == GL_STENCIL_INDEX &&
_mesa_is_format_packed_depth_stencil(strb->Base.Format)) {
/* writing stencil to a combined depth+stencil buffer */
usage = PIPE_TRANSFER_READ_WRITE;
return fpv;
}
+/**
+ * Get fragment program variant for a glDrawPixels command
+ * for COLOR_INDEX data
+ */
+static struct st_fp_variant *
+get_color_index_fp_variant(struct st_context *st)
+{
+ struct gl_context *ctx = st->ctx;
+ struct st_fp_variant_key key;
+ struct st_fp_variant *fpv;
+
+ memset(&key, 0, sizeof(key));
+
+ key.st = st->has_shareable_shaders ? NULL : st;
+ key.drawpixels = 1;
+ /* Since GL is always in RGBA mode MapColorFlag does not
+ * affect GL_COLOR_INDEX format.
+ * Scale and bias also never affect GL_COLOR_INDEX format.
+ */
+ key.scaleAndBias = 0;
+ key.pixelMaps = 0;
+ key.clamp_color = st->clamp_frag_color_in_shader &&
+ ctx->Color._ClampFragmentColor;
+
+ fpv = st_get_fp_variant(st, st->fp, &key);
+
+ return fpv;
+}
+
/**
* Clamp glDrawPixels width and height to the maximum texture size.
clamp_size(struct pipe_context *pipe, GLsizei *width, GLsizei *height,
struct gl_pixelstore_attrib *unpack)
{
- const int maxSize =
- 1 << (pipe->screen->get_param(pipe->screen,
- PIPE_CAP_MAX_TEXTURE_2D_LEVELS) - 1);
+ const int maxSize = pipe->screen->get_param(pipe->screen,
+ PIPE_CAP_MAX_TEXTURE_2D_SIZE);
if (*width > maxSize) {
if (unpack->RowLength == 0)
}
+/**
+ * Compute the effective raster z position. This performs depth-clamping
+ * if needed.
+ */
+static float
+get_effective_raster_z(struct gl_context *ctx)
+{
+ float z = ctx->Current.RasterPos[2];
+ if (st_context(ctx)->clamp_frag_depth_in_shader) {
+ GLfloat depth_near;
+ GLfloat depth_far;
+ if (ctx->ViewportArray[0].Near < ctx->ViewportArray[0].Far) {
+ depth_near = ctx->ViewportArray[0].Near;
+ depth_far = ctx->ViewportArray[0].Far;
+ } else {
+ depth_near = ctx->ViewportArray[0].Far;
+ depth_far = ctx->ViewportArray[0].Near;
+ }
+
+ if (ctx->Transform.DepthClampNear)
+ z = MAX2(z, depth_near);
+ if (ctx->Transform.DepthClampFar)
+ z = MIN2(z, depth_far);
+ }
+ return z;
+}
+
+
/**
* Called via ctx->Driver.DrawPixels()
*/
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack, const void *pixels)
{
- void *driver_vp, *driver_fp;
+ void *driver_fp;
struct st_context *st = st_context(ctx);
struct pipe_context *pipe = st->pipe;
GLboolean write_stencil = GL_FALSE, write_depth = GL_FALSE;
/* Mesa state should be up to date by now */
assert(ctx->NewState == 0x0);
+ _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
+
st_flush_bitmap_cache(st);
st_invalidate_readpix_cache(st);
- st_validate_state(st, ST_PIPELINE_RENDER);
+ st_validate_state(st, ST_PIPELINE_META);
/* Limit the size of the glDrawPixels to the max texture size.
* Strictly speaking, that's not correct but since we don't handle
return;
}
+ /* Put glDrawPixels image into a texture */
+ pt = make_texture(st, width, height, format, type, unpack, pixels);
+ if (!pt) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
+ return;
+ }
+
+ st_make_passthrough_vertex_shader(st);
+
/*
* Get vertex/fragment shaders
*/
if (write_depth || write_stencil) {
driver_fp = get_drawpix_z_stencil_program(st, write_depth,
write_stencil);
- driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
}
else {
- fpv = get_color_fp_variant(st);
+ fpv = (format != GL_COLOR_INDEX) ? get_color_fp_variant(st) :
+ get_color_index_fp_variant(st);
- driver_fp = fpv->driver_shader;
- driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
+ driver_fp = fpv->base.driver_shader;
- if (ctx->Pixel.MapColorFlag) {
+ if (ctx->Pixel.MapColorFlag && format != GL_COLOR_INDEX) {
pipe_sampler_view_reference(&sv[1],
st->pixel_xfer.pixelmap_sampler_view);
num_sampler_view++;
/* compiling a new fragment shader variant added new state constants
* into the constant buffer, we need to update them
*/
- st_upload_constants(st, st->fp->Base.Parameters, MESA_SHADER_FRAGMENT);
- }
-
- /* Put glDrawPixels image into a texture */
- pt = make_texture(st, width, height, format, type, unpack, pixels);
- if (!pt) {
- _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
- return;
+ st_upload_constants(st, &st->fp->Base);
}
/* create sampler view for the image */
num_sampler_view++;
}
- draw_textured_quad(ctx, x, y, ctx->Current.RasterPos[2],
+ draw_textured_quad(ctx, x, y, get_effective_raster_z(ctx),
width, height,
ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
sv,
num_sampler_view,
- driver_vp,
+ st->passthrough_vs,
driver_fp, fpv,
ctx->Current.RasterColor,
GL_FALSE, write_depth, write_stencil);
struct gl_pixelstore_attrib pack, unpack;
GLint readX, readY, readW, readH, drawX, drawY, drawW, drawH;
- if (type == GL_COLOR &&
- ctx->Pixel.ZoomX == 1.0 &&
+ if (ctx->Pixel.ZoomX == 1.0 &&
ctx->Pixel.ZoomY == 1.0 &&
- ctx->_ImageTransferState == 0x0 &&
- !ctx->Color.BlendEnabled &&
- !ctx->Color.AlphaEnabled &&
- (!ctx->Color.ColorLogicOpEnabled || ctx->Color.LogicOp == GL_COPY) &&
- !ctx->Depth.Test &&
- !ctx->Fog.Enabled &&
- !ctx->Stencil.Enabled &&
- !ctx->FragmentProgram.Enabled &&
- !ctx->VertexProgram.Enabled &&
- !ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] &&
- !ctx->ATIFragmentShader._Enabled &&
- ctx->DrawBuffer->_NumColorDrawBuffers == 1 &&
+ (type != GL_COLOR ||
+ (ctx->_ImageTransferState == 0x0 &&
+ !ctx->Color.BlendEnabled &&
+ !ctx->Color.AlphaEnabled &&
+ (!ctx->Color.ColorLogicOpEnabled || ctx->Color.LogicOp == GL_COPY) &&
+ !ctx->Depth.Test &&
+ !ctx->Fog.Enabled &&
+ !ctx->Stencil.Enabled &&
+ !ctx->FragmentProgram.Enabled &&
+ !ctx->VertexProgram.Enabled &&
+ !ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT] &&
+ !_mesa_ati_fragment_shader_enabled(ctx) &&
+ ctx->DrawBuffer->_NumColorDrawBuffers == 1)) &&
!ctx->Query.CondRenderQuery &&
!ctx->Query.CurrentOcclusionObject) {
struct st_renderbuffer *rbRead, *rbDraw;
drawW = readW;
drawH = readH;
- rbRead = st_get_color_read_renderbuffer(ctx);
- rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
+ if (type == GL_COLOR) {
+ rbRead = st_get_color_read_renderbuffer(ctx);
+ rbDraw = st_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0]);
+ } else if (type == GL_DEPTH || type == GL_DEPTH_STENCIL) {
+ rbRead = st_renderbuffer(ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer);
+ rbDraw = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer);
+ } else if (type == GL_STENCIL) {
+ rbRead = st_renderbuffer(ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer);
+ rbDraw = st_renderbuffer(ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer);
+ } else {
+ return false;
+ }
/* Flip src/dst position depending on the orientation of buffers. */
if (st_fb_orientation(ctx->ReadBuffer) == Y_0_TOP) {
blit.dst.box.width = drawW;
blit.dst.box.height = drawH;
blit.dst.box.depth = 1;
- blit.mask = PIPE_MASK_RGBA;
blit.filter = PIPE_TEX_FILTER_NEAREST;
+ if (type == GL_COLOR)
+ blit.mask |= PIPE_MASK_RGBA;
+ if (type == GL_DEPTH)
+ blit.mask |= PIPE_MASK_Z;
+ if (type == GL_STENCIL)
+ blit.mask |= PIPE_MASK_S;
+ if (type == GL_DEPTH_STENCIL)
+ blit.mask |= PIPE_MASK_ZS;
+
if (ctx->DrawBuffer != ctx->WinSysDrawBuffer)
st_window_rectangles_to_blit(ctx, &blit);
if (screen->is_format_supported(screen, blit.src.format,
blit.src.resource->target,
blit.src.resource->nr_samples,
+ blit.src.resource->nr_storage_samples,
PIPE_BIND_SAMPLER_VIEW) &&
screen->is_format_supported(screen, blit.dst.format,
blit.dst.resource->target,
blit.dst.resource->nr_samples,
+ blit.dst.resource->nr_storage_samples,
PIPE_BIND_RENDER_TARGET)) {
pipe->blit(pipe, &blit);
return GL_TRUE;
struct pipe_context *pipe = st->pipe;
struct pipe_screen *screen = pipe->screen;
struct st_renderbuffer *rbRead;
- void *driver_vp, *driver_fp;
+ void *driver_fp;
struct pipe_resource *pt;
struct pipe_sampler_view *sv[2] = { NULL };
struct st_fp_variant *fpv = NULL;
GLboolean invertTex = GL_FALSE;
GLint readX, readY, readW, readH;
struct gl_pixelstore_attrib pack = ctx->DefaultPacking;
+ GLboolean write_stencil = GL_FALSE;
+ GLboolean write_depth = GL_FALSE;
+
+ _mesa_update_draw_buffer_bounds(ctx, ctx->DrawBuffer);
st_flush_bitmap_cache(st);
st_invalidate_readpix_cache(st);
- st_validate_state(st, ST_PIPELINE_RENDER);
+ st_validate_state(st, ST_PIPELINE_META);
+
+ if (blit_copy_pixels(ctx, srcx, srcy, width, height, dstx, dsty, type))
+ return;
if (type == GL_DEPTH_STENCIL) {
/* XXX make this more efficient */
return;
}
- if (type == GL_STENCIL) {
- /* can't use texturing to do stencil */
+ /* fallback if the driver can't do stencil exports */
+ if (type == GL_STENCIL &&
+ !pipe->screen->get_param(pipe->screen, PIPE_CAP_SHADER_STENCIL_EXPORT)) {
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.
* are handled.
*/
+ st_make_passthrough_vertex_shader(st);
/*
* Get vertex/fragment shaders
rbRead = st_get_color_read_renderbuffer(ctx);
- driver_fp = fpv->driver_shader;
- driver_vp = make_passthrough_vertex_shader(st, GL_FALSE);
+ driver_fp = fpv->base.driver_shader;
if (ctx->Pixel.MapColorFlag) {
pipe_sampler_view_reference(&sv[1],
/* compiling a new fragment shader variant added new state constants
* into the constant buffer, we need to update them
*/
- st_upload_constants(st, st->fp->Base.Parameters, MESA_SHADER_FRAGMENT);
- }
- else {
- assert(type == GL_DEPTH);
+ st_upload_constants(st, &st->fp->Base);
+ } else if (type == GL_DEPTH) {
rbRead = st_renderbuffer(ctx->ReadBuffer->
Attachment[BUFFER_DEPTH].Renderbuffer);
-
driver_fp = get_drawpix_z_stencil_program(st, GL_TRUE, GL_FALSE);
- driver_vp = make_passthrough_vertex_shader(st, GL_TRUE);
+ } else {
+ assert(type == GL_STENCIL);
+ rbRead = st_renderbuffer(ctx->ReadBuffer->
+ Attachment[BUFFER_STENCIL].Renderbuffer);
+ driver_fp = get_drawpix_z_stencil_program(st, GL_FALSE, GL_TRUE);
}
/* Choose the format for the temporary texture. */
(type == GL_COLOR ? PIPE_BIND_RENDER_TARGET : PIPE_BIND_DEPTH_STENCIL);
if (!screen->is_format_supported(screen, srcFormat, st->internal_target, 0,
- srcBind)) {
+ 0, srcBind)) {
/* srcFormat is non-renderable. Find a compatible renderable format. */
if (type == GL_DEPTH) {
srcFormat = st_choose_format(st, GL_DEPTH_COMPONENT, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
+ }
+ else if (type == GL_STENCIL) {
+ /* can't use texturing, fallback to copy */
+ copy_stencil_pixels(ctx, srcx, srcy, width, height, dstx, dsty);
+ return;
}
else {
assert(type == GL_COLOR);
if (util_format_is_float(srcFormat)) {
srcFormat = st_choose_format(st, GL_RGBA32F, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
}
else if (util_format_is_pure_sint(srcFormat)) {
srcFormat = st_choose_format(st, GL_RGBA32I, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
}
else if (util_format_is_pure_uint(srcFormat)) {
srcFormat = st_choose_format(st, GL_RGBA32UI, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
}
else if (util_format_is_snorm(srcFormat)) {
srcFormat = st_choose_format(st, GL_RGBA16_SNORM, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
}
else {
srcFormat = st_choose_format(st, GL_RGBA, GL_NONE,
- GL_NONE, st->internal_target, 0,
- srcBind, FALSE);
+ GL_NONE, st->internal_target, 0, 0,
+ srcBind, false, false);
}
}
return;
}
+ /* Create a second sampler view to read stencil */
+ if (type == GL_STENCIL) {
+ write_stencil = GL_TRUE;
+ enum pipe_format stencil_format =
+ util_format_stencil_only(pt->format);
+ /* we should not be doing pixel map/transfer (see above) */
+ assert(num_sampler_view == 1);
+ sv[1] = st_create_texture_sampler_view_format(st->pipe, pt,
+ stencil_format);
+ if (!sv[1]) {
+ _mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
+ pipe_resource_reference(&pt, NULL);
+ pipe_sampler_view_reference(&sv[0], NULL);
+ return;
+ }
+ num_sampler_view++;
+ }
/* Copy the src region to the temporary texture. */
{
struct pipe_blit_info blit;
blit.dst.box.width = readW;
blit.dst.box.height = readH;
blit.dst.box.depth = 1;
- blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S;
+ if (type != GL_STENCIL)
+ blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_S;
+ else
+ blit.mask = util_format_get_mask(pt->format) & ~PIPE_MASK_Z;
blit.filter = PIPE_TEX_FILTER_NEAREST;
pipe->blit(pipe, &blit);
/* 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],
+
+ draw_textured_quad(ctx, dstx, dsty, get_effective_raster_z(ctx),
width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY,
sv,
num_sampler_view,
- driver_vp,
+ st->passthrough_vs,
driver_fp, fpv,
ctx->Current.Attrib[VERT_ATTRIB_COLOR0],
- invertTex, GL_FALSE, GL_FALSE);
+ invertTex, write_depth, write_stencil);
pipe_resource_reference(&pt, NULL);
pipe_sampler_view_reference(&sv[0], NULL);
for (i = 0; i < ARRAY_SIZE(st->drawpix.zs_shaders); i++) {
if (st->drawpix.zs_shaders[i])
- cso_delete_fragment_shader(st->cso_context,
- st->drawpix.zs_shaders[i]);
+ st->pipe->delete_fs_state(st->pipe, st->drawpix.zs_shaders[i]);
}
- if (st->drawpix.vert_shaders[0])
- cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[0]);
- if (st->drawpix.vert_shaders[1])
- cso_delete_vertex_shader(st->cso_context, st->drawpix.vert_shaders[1]);
+ if (st->passthrough_vs)
+ st->pipe->delete_vs_state(st->pipe, st->passthrough_vs);
+
+ /* Free cache data */
+ for (i = 0; i < ARRAY_SIZE(st->drawpix_cache.entries); i++) {
+ struct drawpix_cache_entry *entry = &st->drawpix_cache.entries[i];
+ free(entry->image);
+ pipe_resource_reference(&entry->texture, NULL);
+ }
}