summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--src/gallium/auxiliary/util/u_vbuf_mgr.c10
-rw-r--r--src/gallium/auxiliary/vl/vl_compositor.c25
-rw-r--r--src/gallium/auxiliary/vl/vl_compositor.h1
-rw-r--r--src/gallium/auxiliary/vl/vl_idct.c3
-rw-r--r--src/gallium/auxiliary/vl/vl_mc.c13
-rw-r--r--src/gallium/drivers/nouveau/Makefile3
-rw-r--r--src/gallium/drivers/nouveau/nouveau_context.h3
-rw-r--r--src/gallium/drivers/nouveau/nouveau_screen.h1
-rw-r--r--src/gallium/drivers/nouveau/nouveau_video.c39
-rw-r--r--src/gallium/drivers/nv50/nv50_context.c2
-rw-r--r--src/gallium/drivers/nv50/nv50_screen.c2
-rw-r--r--src/gallium/drivers/nvc0/nvc0_context.c2
-rw-r--r--src/gallium/drivers/nvc0/nvc0_screen.c5
-rw-r--r--src/gbm/main/gbm.h9
-rw-r--r--src/glsl/Makefile1
-rw-r--r--src/glsl/SConscript1
-rw-r--r--src/glsl/ast_function.cpp6
-rw-r--r--src/glsl/ast_to_hir.cpp2
-rw-r--r--src/glsl/ir.h30
-rw-r--r--src/glsl/ir_function_detect_recursion.cpp371
-rw-r--r--src/glsl/linker.cpp6
-rw-r--r--src/glsl/s_expression.cpp64
-rw-r--r--src/glsl/s_expression.h2
-rw-r--r--src/mesa/drivers/common/meta.c160
-rw-r--r--src/mesa/drivers/common/meta.h3
-rw-r--r--src/mesa/drivers/dri/i965/gen6_vs_state.c26
-rw-r--r--src/mesa/drivers/dri/intel/intel_batchbuffer.c33
-rw-r--r--src/mesa/drivers/dri/intel/intel_clear.c5
-rw-r--r--src/mesa/drivers/dri/intel/intel_reg.h1
-rw-r--r--src/mesa/main/fbobject.c23
31 files changed, 810 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index b0a2d8065f6..817f3d3706a 100644
--- a/Makefile
+++ b/Makefile
@@ -203,12 +203,6 @@ EXTRA_FILES = \
IGNORE_FILES = \
-x autogen.sh
-DEPEND_FILES = \
- src/mesa/depend \
- src/glx/depend \
- src/glw/depend \
- src/glu/sgi/depend
-
parsers: configure
-@touch $(TOP)/configs/current
@@ -231,15 +225,9 @@ AUTOCONF = autoconf
AC_FLAGS =
aclocal.m4: configure.ac acinclude.m4
$(ACLOCAL) $(ACLOCAL_FLAGS)
-configure: rm_depend configure.ac aclocal.m4 acinclude.m4
+configure: configure.ac aclocal.m4 acinclude.m4
$(AUTOCONF) $(AC_FLAGS)
-rm_depend:
- @for dep in $(DEPEND_FILES) ; do \
- rm -f $$dep ; \
- touch $$dep ; \
- done
-
manifest.txt: .git
( \
ls -1 $(EXTRA_FILES) ; \
@@ -269,4 +257,4 @@ md5: $(ARCHIVES)
@-md5sum $(PACKAGE_NAME).tar.bz2
@-md5sum $(PACKAGE_NAME).zip
-.PHONY: tarballs rm_depend md5
+.PHONY: tarballs md5
diff --git a/src/gallium/auxiliary/util/u_vbuf_mgr.c b/src/gallium/auxiliary/util/u_vbuf_mgr.c
index 374fc336b83..19eb689cfb2 100644
--- a/src/gallium/auxiliary/util/u_vbuf_mgr.c
+++ b/src/gallium/auxiliary/util/u_vbuf_mgr.c
@@ -79,6 +79,8 @@ struct u_vbuf_mgr_priv {
void *saved_ve, *fallback_ve;
boolean ve_binding_lock;
+ unsigned saved_buffer_offset[PIPE_MAX_ATTRIBS];
+
boolean any_user_vbs;
boolean incompatible_vb_layout;
};
@@ -488,6 +490,7 @@ void u_vbuf_mgr_set_vertex_buffers(struct u_vbuf_mgr *mgrb,
pipe_resource_reference(&mgr->b.vertex_buffer[i].buffer, vb->buffer);
pipe_resource_reference(&mgr->b.real_vertex_buffer[i], NULL);
+ mgr->saved_buffer_offset[i] = vb->buffer_offset;
if (!vb->buffer) {
continue;
@@ -647,6 +650,13 @@ u_vbuf_mgr_draw_begin(struct u_vbuf_mgr *mgrb,
void u_vbuf_mgr_draw_end(struct u_vbuf_mgr *mgrb)
{
struct u_vbuf_mgr_priv *mgr = (struct u_vbuf_mgr_priv*)mgrb;
+ unsigned i;
+
+ /* buffer offsets were modified in u_vbuf_upload_buffers */
+ if (mgr->any_user_vbs) {
+ for (i = 0; i < mgr->b.nr_vertex_buffers; i++)
+ mgr->b.vertex_buffer[i].buffer_offset = mgr->saved_buffer_offset[i];
+ }
if (mgr->fallback_ve) {
u_vbuf_translate_end(mgr);
diff --git a/src/gallium/auxiliary/vl/vl_compositor.c b/src/gallium/auxiliary/vl/vl_compositor.c
index 3bd4af2e3e0..faca96dc55b 100644
--- a/src/gallium/auxiliary/vl/vl_compositor.c
+++ b/src/gallium/auxiliary/vl/vl_compositor.c
@@ -231,6 +231,8 @@ init_pipe_state(struct vl_compositor *c)
struct pipe_rasterizer_state rast;
struct pipe_sampler_state sampler;
struct pipe_blend_state blend;
+ struct pipe_depth_stencil_alpha_state dsa;
+ unsigned i;
assert(c);
@@ -289,6 +291,24 @@ init_pipe_state(struct vl_compositor *c)
c->rast = c->pipe->create_rasterizer_state(c->pipe, &rast);
+ memset(&dsa, 0, sizeof dsa);
+ dsa.depth.enabled = 0;
+ dsa.depth.writemask = 0;
+ dsa.depth.func = PIPE_FUNC_ALWAYS;
+ for (i = 0; i < 2; ++i) {
+ dsa.stencil[i].enabled = 0;
+ dsa.stencil[i].func = PIPE_FUNC_ALWAYS;
+ dsa.stencil[i].fail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zpass_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].zfail_op = PIPE_STENCIL_OP_KEEP;
+ dsa.stencil[i].valuemask = 0;
+ dsa.stencil[i].writemask = 0;
+ }
+ dsa.alpha.enabled = 0;
+ dsa.alpha.func = PIPE_FUNC_ALWAYS;
+ dsa.alpha.ref_value = 0;
+ c->dsa = c->pipe->create_depth_stencil_alpha_state(c->pipe, &dsa);
+ c->pipe->bind_depth_stencil_alpha_state(c->pipe, c->dsa);
return true;
}
@@ -296,6 +316,11 @@ static void cleanup_pipe_state(struct vl_compositor *c)
{
assert(c);
+ /* Asserted in softpipe_delete_fs_state() for some reason */
+ c->pipe->bind_vs_state(c->pipe, NULL);
+ c->pipe->bind_fs_state(c->pipe, NULL);
+
+ c->pipe->delete_depth_stencil_alpha_state(c->pipe, c->dsa);
c->pipe->delete_sampler_state(c->pipe, c->sampler_linear);
c->pipe->delete_sampler_state(c->pipe, c->sampler_nearest);
c->pipe->delete_blend_state(c->pipe, c->blend);
diff --git a/src/gallium/auxiliary/vl/vl_compositor.h b/src/gallium/auxiliary/vl/vl_compositor.h
index 87ad39be1be..0a9a7411a61 100644
--- a/src/gallium/auxiliary/vl/vl_compositor.h
+++ b/src/gallium/auxiliary/vl/vl_compositor.h
@@ -68,6 +68,7 @@ struct vl_compositor
void *sampler_nearest;
void *blend;
void *rast;
+ void *dsa;
void *vertex_elems_state;
void *vs;
diff --git a/src/gallium/auxiliary/vl/vl_idct.c b/src/gallium/auxiliary/vl/vl_idct.c
index 645d06a0925..ad786145392 100644
--- a/src/gallium/auxiliary/vl/vl_idct.c
+++ b/src/gallium/auxiliary/vl/vl_idct.c
@@ -143,7 +143,7 @@ static void *
create_mismatch_vert_shader(struct vl_idct *idct)
{
struct ureg_program *shader;
- struct ureg_src vrect, vpos;
+ struct ureg_src vpos;
struct ureg_src scale;
struct ureg_dst t_tex;
struct ureg_dst o_vpos, o_addr[2];
@@ -152,7 +152,6 @@ create_mismatch_vert_shader(struct vl_idct *idct)
if (!shader)
return NULL;
- vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vpos = ureg_DECL_vs_input(shader, VS_I_VPOS);
t_tex = ureg_DECL_temporary(shader);
diff --git a/src/gallium/auxiliary/vl/vl_mc.c b/src/gallium/auxiliary/vl/vl_mc.c
index bd05205b52d..81a05b539f3 100644
--- a/src/gallium/auxiliary/vl/vl_mc.c
+++ b/src/gallium/auxiliary/vl/vl_mc.c
@@ -103,7 +103,7 @@ create_ref_vert_shader(struct vl_mc *r)
{
struct ureg_program *shader;
struct ureg_src mv_scale;
- struct ureg_src vrect, vmv[2];
+ struct ureg_src vmv[2];
struct ureg_dst t_vpos;
struct ureg_dst o_vpos, o_vmv[2];
unsigned i;
@@ -112,7 +112,6 @@ create_ref_vert_shader(struct vl_mc *r)
if (!shader)
return NULL;
- vrect = ureg_DECL_vs_input(shader, VS_I_RECT);
vmv[0] = ureg_DECL_vs_input(shader, VS_I_MV_TOP);
vmv[1] = ureg_DECL_vs_input(shader, VS_I_MV_BOTTOM);
@@ -121,6 +120,8 @@ create_ref_vert_shader(struct vl_mc *r)
(float)MACROBLOCK_HEIGHT / r->buffer_height)
);
+ /* XXX The position is not written, which may lead to undefined rendering.
+ * XXX This is a serious bug. */
o_vpos = ureg_DECL_output(shader, TGSI_SEMANTIC_POSITION, VS_O_VPOS);
o_vmv[0] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VTOP);
o_vmv[1] = ureg_DECL_output(shader, TGSI_SEMANTIC_GENERIC, VS_O_VBOTTOM);
@@ -590,7 +591,7 @@ vl_mc_set_surface(struct vl_mc_buffer *buffer, struct pipe_surface *surface)
}
static void
-prepare_pipe_4_rendering(struct vl_mc_buffer *buffer, unsigned mask)
+prepare_pipe_4_rendering(struct vl_mc_buffer *buffer, unsigned component, unsigned mask)
{
struct vl_mc *renderer;
@@ -599,7 +600,7 @@ prepare_pipe_4_rendering(struct vl_mc_buffer *buffer, unsigned mask)
renderer = buffer->renderer;
renderer->pipe->bind_rasterizer_state(renderer->pipe, renderer->rs_state);
- if (buffer->surface_cleared)
+ if (buffer->surface_cleared || component > 0)
renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_add[mask]);
else
renderer->pipe->bind_blend_state(renderer->pipe, renderer->blend_clear[mask]);
@@ -615,7 +616,7 @@ vl_mc_render_ref(struct vl_mc_buffer *buffer, struct pipe_sampler_view *ref)
assert(buffer && ref);
- prepare_pipe_4_rendering(buffer, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
+ prepare_pipe_4_rendering(buffer, 0, PIPE_MASK_R | PIPE_MASK_G | PIPE_MASK_B);
renderer = buffer->renderer;
@@ -643,7 +644,7 @@ vl_mc_render_ycbcr(struct vl_mc_buffer *buffer, unsigned component, unsigned num
if (num_instances == 0)
return;
- prepare_pipe_4_rendering(buffer, mask);
+ prepare_pipe_4_rendering(buffer, component, mask);
renderer = buffer->renderer;
diff --git a/src/gallium/drivers/nouveau/Makefile b/src/gallium/drivers/nouveau/Makefile
index 3210d1ff77b..aae6d9889bb 100644
--- a/src/gallium/drivers/nouveau/Makefile
+++ b/src/gallium/drivers/nouveau/Makefile
@@ -10,6 +10,7 @@ LIBRARY_INCLUDES = \
C_SOURCES = nouveau_screen.c \
nouveau_fence.c \
nouveau_mm.c \
- nouveau_buffer.c
+ nouveau_buffer.c \
+ nouveau_video.c
include ../../Makefile.template
diff --git a/src/gallium/drivers/nouveau/nouveau_context.h b/src/gallium/drivers/nouveau/nouveau_context.h
index 696e0d3f24e..19bf7c84ac7 100644
--- a/src/gallium/drivers/nouveau/nouveau_context.h
+++ b/src/gallium/drivers/nouveau/nouveau_context.h
@@ -23,4 +23,7 @@ nouveau_context(struct pipe_context *pipe)
return (struct nouveau_context *)pipe;
}
+void
+nouveau_context_init_vdec(struct nouveau_context *);
+
#endif
diff --git a/src/gallium/drivers/nouveau/nouveau_screen.h b/src/gallium/drivers/nouveau/nouveau_screen.h
index d910809a0ec..cf291c6c595 100644
--- a/src/gallium/drivers/nouveau/nouveau_screen.h
+++ b/src/gallium/drivers/nouveau/nouveau_screen.h
@@ -76,6 +76,7 @@ nouveau_screen_bo_from_handle(struct pipe_screen *pscreen,
int nouveau_screen_init(struct nouveau_screen *, struct nouveau_device *);
void nouveau_screen_fini(struct nouveau_screen *);
+void nouveau_screen_init_vdec(struct nouveau_screen *);
#ifndef NOUVEAU_NVC0
diff --git a/src/gallium/drivers/nouveau/nouveau_video.c b/src/gallium/drivers/nouveau/nouveau_video.c
new file mode 100644
index 00000000000..32f038dae61
--- /dev/null
+++ b/src/gallium/drivers/nouveau/nouveau_video.c
@@ -0,0 +1,39 @@
+
+#include "vl/vl_decoder.h"
+#include "vl/vl_video_buffer.h"
+
+#include "nouveau/nouveau_screen.h"
+#include "nouveau/nouveau_context.h"
+
+static int
+nouveau_screen_get_video_param(struct pipe_screen *pscreen,
+ enum pipe_video_profile profile,
+ enum pipe_video_cap param)
+{
+ switch (param) {
+ case PIPE_VIDEO_CAP_SUPPORTED:
+ return vl_profile_supported(pscreen, profile);
+ case PIPE_VIDEO_CAP_NPOT_TEXTURES:
+ return 1;
+ case PIPE_VIDEO_CAP_MAX_WIDTH:
+ case PIPE_VIDEO_CAP_MAX_HEIGHT:
+ return vl_video_buffer_max_size(pscreen);
+ default:
+ debug_printf("unknown video param: %d\n", param);
+ return 0;
+ }
+}
+
+void
+nouveau_screen_init_vdec(struct nouveau_screen *screen)
+{
+ screen->base.get_video_param = nouveau_screen_get_video_param;
+ screen->base.is_video_format_supported = vl_video_buffer_is_format_supported;
+}
+
+void
+nouveau_context_init_vdec(struct nouveau_context *nv)
+{
+ nv->pipe.create_video_decoder = vl_create_decoder;
+ nv->pipe.create_video_buffer = vl_video_buffer_create;
+}
diff --git a/src/gallium/drivers/nv50/nv50_context.c b/src/gallium/drivers/nv50/nv50_context.c
index ac3e361a446..0d464063b5b 100644
--- a/src/gallium/drivers/nv50/nv50_context.c
+++ b/src/gallium/drivers/nv50/nv50_context.c
@@ -149,6 +149,8 @@ nv50_create(struct pipe_screen *pscreen, void *priv)
assert(nv50->draw);
draw_set_rasterize_stage(nv50->draw, nv50_draw_render_stage(nv50));
+ nouveau_context_init_vdec(&nv50->base);
+
return pipe;
}
diff --git a/src/gallium/drivers/nv50/nv50_screen.c b/src/gallium/drivers/nv50/nv50_screen.c
index a697ff5ecf7..4139b85a9ae 100644
--- a/src/gallium/drivers/nv50/nv50_screen.c
+++ b/src/gallium/drivers/nv50/nv50_screen.c
@@ -315,6 +315,8 @@ nv50_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
nv50_screen_init_resource_functions(pscreen);
+ nouveau_screen_init_vdec(&screen->base);
+
ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096,
&screen->fence.bo);
if (ret)
diff --git a/src/gallium/drivers/nvc0/nvc0_context.c b/src/gallium/drivers/nvc0/nvc0_context.c
index 983db23eedb..360afbb943e 100644
--- a/src/gallium/drivers/nvc0/nvc0_context.c
+++ b/src/gallium/drivers/nvc0/nvc0_context.c
@@ -150,6 +150,8 @@ nvc0_create(struct pipe_screen *pscreen, void *priv)
assert(nvc0->draw);
draw_set_rasterize_stage(nvc0->draw, nvc0_draw_render_stage(nvc0));
+ nouveau_context_init_vdec(&nvc0->base);
+
return pipe;
}
diff --git a/src/gallium/drivers/nvc0/nvc0_screen.c b/src/gallium/drivers/nvc0/nvc0_screen.c
index 605a0b04018..5d1b324dbff 100644
--- a/src/gallium/drivers/nvc0/nvc0_screen.c
+++ b/src/gallium/drivers/nvc0/nvc0_screen.c
@@ -24,6 +24,9 @@
#include "util/u_format_s3tc.h"
#include "pipe/p_screen.h"
+#include "vl/vl_decoder.h"
+#include "vl/vl_video_buffer.h"
+
#include "nvc0_context.h"
#include "nvc0_screen.h"
@@ -373,6 +376,8 @@ nvc0_screen_create(struct pipe_winsys *ws, struct nouveau_device *dev)
nvc0_screen_init_resource_functions(pscreen);
+ nouveau_screen_init_vdec(&screen->base);
+
ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 4096,
&screen->fence.bo);
if (ret)
diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h
index d79a03e4b3f..05d2292dc75 100644
--- a/src/gbm/main/gbm.h
+++ b/src/gbm/main/gbm.h
@@ -28,6 +28,11 @@
#ifndef _GBM_H_
#define _GBM_H_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
#define __GBM__ 1
#include <stdint.h>
@@ -97,4 +102,8 @@ gbm_bo_get_handle(struct gbm_bo *bo);
void
gbm_bo_destroy(struct gbm_bo *bo);
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/src/glsl/Makefile b/src/glsl/Makefile
index e0776c1b55d..d1422c2a4d6 100644
--- a/src/glsl/Makefile
+++ b/src/glsl/Makefile
@@ -39,6 +39,7 @@ CXX_SOURCES = \
ir.cpp \
ir_expression_flattening.cpp \
ir_function_can_inline.cpp \
+ ir_function_detect_recursion.cpp \
ir_function.cpp \
ir_hierarchical_visitor.cpp \
ir_hv_accept.cpp \
diff --git a/src/glsl/SConscript b/src/glsl/SConscript
index 1441cc74bd8..ea104abb823 100644
--- a/src/glsl/SConscript
+++ b/src/glsl/SConscript
@@ -50,6 +50,7 @@ glsl_sources = [
'ir.cpp',
'ir_expression_flattening.cpp',
'ir_function_can_inline.cpp',
+ 'ir_function_detect_recursion.cpp',
'ir_function.cpp',
'ir_hierarchical_visitor.cpp',
'ir_hv_accept.cpp',
diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp
index 60a2c617f70..bdb73f48706 100644
--- a/src/glsl/ast_function.cpp
+++ b/src/glsl/ast_function.cpp
@@ -62,8 +62,10 @@ process_parameters(exec_list *instructions, exec_list *actual_parameters,
*
* \param return_type Return type of the function. May be \c NULL.
* \param name Name of the function.
- * \param parameters Parameter list for the function. This may be either a
- * formal or actual parameter list. Only the type is used.
+ * \param parameters List of \c ir_instruction nodes representing the
+ * parameter list for the function. This may be either a
+ * formal (\c ir_variable) or actual (\c ir_rvalue)
+ * parameter list. Only the type is used.
*
* \return
* A ralloced string representing the prototype of the function.
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 2312c297c40..c0524bf0bcc 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -83,6 +83,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
foreach_list_typed (ast_node, ast, link, & state->translation_unit)
ast->hir(instructions, state);
+
+ detect_recursion_unlinked(state, instructions);
}
diff --git a/src/glsl/ir.h b/src/glsl/ir.h
index 80ad3dd295e..50a9d6e1991 100644
--- a/src/glsl/ir.h
+++ b/src/glsl/ir.h
@@ -1635,6 +1635,32 @@ visit_exec_list(exec_list *list, ir_visitor *visitor);
*/
void validate_ir_tree(exec_list *instructions);
+struct _mesa_glsl_parse_state;
+struct gl_shader_program;
+
+/**
+ * Detect whether an unlinked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c _mesa_glsl_error will be called to emit error messages for each function
+ * that is in the recursion cycle.
+ */
+void
+detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions);
+
+/**
+ * Detect whether a linked shader contains static recursion
+ *
+ * If the list of instructions is determined to contain static recursion,
+ * \c link_error_printf will be called to emit error messages for each function
+ * that is in the recursion cycle. In addition,
+ * \c gl_shader_program::LinkStatus will be set to false.
+ */
+void
+detect_recursion_linked(struct gl_shader_program *prog,
+ exec_list *instructions);
+
/**
* Make a clone of each IR instruction in a list
*
@@ -1669,4 +1695,8 @@ ir_has_call(ir_instruction *ir);
extern void
do_set_program_inouts(exec_list *instructions, struct gl_program *prog);
+extern char *
+prototype_string(const glsl_type *return_type, const char *name,
+ exec_list *parameters);
+
#endif /* IR_H */
diff --git a/src/glsl/ir_function_detect_recursion.cpp b/src/glsl/ir_function_detect_recursion.cpp
new file mode 100644
index 00000000000..44a1cd0b950
--- /dev/null
+++ b/src/glsl/ir_function_detect_recursion.cpp
@@ -0,0 +1,371 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * 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 without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * 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 NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 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.
+ */
+
+/**
+ * \file ir_function_detect_recursion.cpp
+ * Determine whether a shader contains static recursion.
+ *
+ * Consider the (possibly disjoint) graph of function calls in a shader. If a
+ * program contains recursion, this graph will contain a cycle. If a function
+ * is part of a cycle, it will have a caller and it will have a callee (it
+ * calls another function).
+ *
+ * To detect recursion, the function call graph is constructed. The graph is
+ * repeatedly reduced by removing any function that either has no callees
+ * (leaf functions) or has no caller. Eventually the only functions that
+ * remain will be the functions in the cycles.
+ *
+ * The GLSL spec is a bit wishy-washy about recursion.
+ *
+ * From page 39 (page 45 of the PDF) of the GLSL 1.10 spec:
+ *
+ * "Behavior is undefined if recursion is used. Recursion means having any
+ * function appearing more than once at any one time in the run-time stack
+ * of function calls. That is, a function may not call itself either
+ * directly or indirectly. Compilers may give diagnostic messages when
+ * this is detectable at compile time, but not all such cases can be
+ * detected at compile time."
+ *
+ * From page 79 (page 85 of the PDF):
+ *
+ * "22) Should recursion be supported?
+ *
+ * DISCUSSION: Probably not necessary, but another example of limiting
+ * the language based on how it would directly map to hardware. One
+ * thought is that recursion would benefit ray tracing shaders. On the
+ * other hand, many recursion operations can also be implemented with the
+ * user managing the recursion through arrays. RenderMan doesn't support
+ * recursion. This could be added at a later date, if it proved to be
+ * necessary.
+ *
+ * RESOLVED on September 10, 2002: Implementations are not required to
+ * support recursion.
+ *
+ * CLOSED on September 10, 2002."
+ *
+ * From page 79 (page 85 of the PDF):
+ *
+ * "56) Is it an error for an implementation to support recursion if the
+ * specification says recursion is not supported?
+ *
+ * ADDED on September 10, 2002.
+ *
+ * DISCUSSION: This issues is related to Issue (22). If we say that
+ * recursion (or some other piece of functionality) is not supported, is
+ * it an error for an implementation to support it? Perhaps the
+ * specification should remain silent on these kind of things so that they
+ * could be gracefully added later as an extension or as part of the
+ * standard.
+ *
+ * RESOLUTION: Languages, in general, have programs that are not
+ * well-formed in ways a compiler cannot detect. Portability is only
+ * ensured for well-formed programs. Detecting recursion is an example of
+ * this. The language will say a well-formed program may not recurse, but
+ * compilers are not forced to detect that recursion may happen.
+ *
+ * CLOSED: November 29, 2002."
+ *
+ * In GLSL 1.10 the behavior of recursion is undefined. Compilers don't have
+ * to reject shaders (at compile-time or link-time) that contain recursion.
+ * Instead they could work, or crash, or kill a kitten.
+ *
+ * From page 44 (page 50 of the PDF) of the GLSL 1.20 spec:
+ *
+ * "Recursion is not allowed, not even statically. Static recursion is
+ * present if the static function call graph of the program contains
+ * cycles."
+ *
+ * This langauge clears things up a bit, but it still leaves a lot of
+ * questions unanswered.
+ *
+ * - Is the error generated at compile-time or link-time?
+ *
+ * - Is it an error to have a recursive function that is never statically
+ * called by main or any function called directly or indirectly by main?
+ * Technically speaking, such a function is not in the "static function
+ * call graph of the program" at all.
+ *
+ * \bug
+ * If a shader has multiple cycles, this algorithm may erroneously complain
+ * about functions that aren't in any cycle, but are in the part of the call
+ * tree that connects them. For example, if the call graph consists of a
+ * cycle between A and B, and a cycle between D and E, and B also calls C
+ * which calls D, then this algorithm will report C as a function which "has
+ * static recursion" even though it is not part of any cycle.
+ *
+ * A better algorithm for cycle detection that doesn't have this drawback can
+ * be found here:
+ *
+ * http://en.wikipedia.org/wiki/Tarjan%E2%80%99s_strongly_connected_components_algorithm
+ *
+ * \author Ian Romanick <[email protected]>
+ */
+#include "main/core.h"
+#include "ir.h"
+#include "glsl_parser_extras.h"
+#include "linker.h"
+#include "program/hash_table.h"
+
+struct call_node : public exec_node {
+ class function *func;
+};
+
+class function {
+public:
+ function(ir_function_signature *sig)
+ : sig(sig)
+ {
+ /* empty */
+ }
+
+
+ /* Callers of this ralloc-based new need not call delete. It's
+ * easier to just ralloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = ralloc_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ /* If the user *does* call delete, that's OK, we will just
+ * ralloc_free in that case. */
+ static void operator delete(void *node)
+ {
+ ralloc_free(node);
+ }
+
+ ir_function_signature *sig;
+
+ /** List of functions called by this function. */
+ exec_list callees;
+
+ /** List of functions that call this function. */
+ exec_list callers;
+};
+
+class has_recursion_visitor : public ir_hierarchical_visitor {
+public:
+ has_recursion_visitor()
+ : current(NULL)
+ {
+ this->mem_ctx = ralloc_context(NULL);
+ this->function_hash = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
+ }
+
+ ~has_recursion_visitor()
+ {
+ hash_table_dtor(this->function_hash);
+ ralloc_free(this->mem_ctx);
+ }
+
+ function *get_function(ir_function_signature *sig)
+ {
+ function *f = (function *) hash_table_find(this->function_hash, sig);
+ if (f == NULL) {
+ f = new(mem_ctx) function(sig);
+ hash_table_insert(this->function_hash, f, sig);
+ }
+
+ return f;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_function_signature *sig)
+ {
+ this->current = this->get_function(sig);
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_function_signature *sig)
+ {
+ (void) sig;
+ this->current = NULL;
+ return visit_continue;
+ }
+
+ virtual ir_visitor_status visit_enter(ir_call *call)
+ {
+ /* At global scope this->current will be NULL. Since there is no way to
+ * call global scope, it can never be part of a cycle. Don't bother
+ * adding calls from global scope to the graph.
+ */
+ if (this->current == NULL)
+ return visit_continue;
+
+ function *const target = this->get_function(call->get_callee());
+
+ /* Create a link from the caller to the callee.
+ */
+ call_node *node = new(mem_ctx) call_node;
+ node->func = target;
+ this->current->callees.push_tail(node);
+
+ /* Create a link from the callee to the caller.
+ */
+ node = new(mem_ctx) call_node;
+ node->func = this->current;
+ target->callers.push_tail(node);
+ return visit_continue;
+ }
+
+ function *current;
+ struct hash_table *function_hash;
+ void *mem_ctx;
+ bool progress;
+};
+
+static void
+destroy_links(exec_list *list, function *f)
+{
+ foreach_list_safe(node, list) {
+ struct call_node *n = (struct call_node *) node;
+
+ /* If this is the right function, remove it. Note that the loop cannot
+ * terminate now. There can be multiple links to a function if it is
+ * either called multiple times or calls multiple times.
+ */
+ if (n->func == f)
+ n->remove();
+ }
+}
+
+
+/**
+ * Remove a function if it has either no in or no out links
+ */
+static void
+remove_unlinked_functions(const void *key, void *data, void *closure)
+{
+ has_recursion_visitor *visitor = (has_recursion_visitor *) closure;
+ function *f = (function *) data;
+
+ if (f->callers.is_empty() || f->callees.is_empty()) {
+ while (!f->callers.is_empty()) {
+ struct call_node *n = (struct call_node *) f->callers.pop_head();
+ destroy_links(& n->func->callees, f);
+ }
+
+ while (!f->callees.is_empty()) {
+ struct call_node *n = (struct call_node *) f->callees.pop_head();
+ destroy_links(& n->func->callers, f);
+ }
+
+ hash_table_remove(visitor->function_hash, key);
+ visitor->progress = true;
+ }
+}
+
+
+static void
+emit_errors_unlinked(const void *key, void *data, void *closure)
+{
+ struct _mesa_glsl_parse_state *state =
+ (struct _mesa_glsl_parse_state *) closure;
+ function *f = (function *) data;
+ YYLTYPE loc;
+
+ char *proto = prototype_string(f->sig->return_type,
+ f->sig->function_name(),
+ &f->sig->parameters);
+
+ memset(&loc, 0, sizeof(loc));
+ _mesa_glsl_error(&loc, state,
+ "function `%s' has static recursion.",
+ proto);
+ ralloc_free(proto);
+}
+
+
+static void
+emit_errors_linked(const void *key, void *data, void *closure)
+{
+ struct gl_shader_program *prog =
+ (struct gl_shader_program *) closure;
+ function *f = (function *) data;
+
+ char *proto = prototype_string(f->sig->return_type,
+ f->sig->function_name(),
+ &f->sig->parameters);
+
+ linker_error_printf(prog,
+ "function `%s' has static recursion.\n",
+ proto);
+ ralloc_free(proto);
+ prog->LinkStatus = false;
+}
+
+
+void
+detect_recursion_unlinked(struct _mesa_glsl_parse_state *state,
+ exec_list *instructions)
+{
+ has_recursion_visitor v;
+
+ /* Collect all of the information about which functions call which other
+ * functions.
+ */
+ v.run(instructions);
+
+ /* Remove from the set all of the functions that either have no caller or
+ * call no other functions. Repeat until no functions are removed.
+ */
+ do {
+ v.progress = false;
+ hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
+ } while (v.progress);
+
+
+ /* At this point any functions still in the hash must be part of a cycle.
+ */
+ hash_table_call_foreach(v.function_hash, emit_errors_unlinked, state);
+}
+
+
+void
+detect_recursion_linked(struct gl_shader_program *prog,
+ exec_list *instructions)
+{
+ has_recursion_visitor v;
+
+ /* Collect all of the information about which functions call which other
+ * functions.
+ */
+ v.run(instructions);
+
+ /* Remove from the set all of the functions that either have no caller or
+ * call no other functions. Repeat until no functions are removed.
+ */
+ do {
+ v.progress = false;
+ hash_table_call_foreach(v.function_hash, remove_unlinked_functions, & v);
+ } while (v.progress);
+
+
+ /* At this point any functions still in the hash must be part of a cycle.
+ */
+ hash_table_call_foreach(v.function_hash, emit_errors_linked, prog);
+}
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index 34b64837a46..fe570b6cc45 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1343,7 +1343,7 @@ assign_attribute_or_color_locations(gl_shader_program *prog,
foreach_list(node, sh->ir) {
ir_variable *const var = ((ir_instruction *) node)->as_variable();
- if ((var == NULL) || (var->mode != direction))
+ if ((var == NULL) || (var->mode != (unsigned) direction))
continue;
if (var->explicit_location) {
@@ -1702,6 +1702,10 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
if (prog->_LinkedShaders[i] == NULL)
continue;
+ detect_recursion_linked(prog, prog->_LinkedShaders[i]->ir);
+ if (!prog->LinkStatus)
+ goto done;
+
while (do_common_optimization(prog->_LinkedShaders[i]->ir, true, 32))
;
}
diff --git a/src/glsl/s_expression.cpp b/src/glsl/s_expression.cpp
index a922a50d3b9..e704a3be20d 100644
--- a/src/glsl/s_expression.cpp
+++ b/src/glsl/s_expression.cpp
@@ -25,10 +25,13 @@
#include <assert.h>
#include "s_expression.h"
-s_symbol::s_symbol(const char *tmp, size_t n)
+s_symbol::s_symbol(const char *str, size_t n)
{
- this->str = ralloc_strndup (this, tmp, n);
- assert(this->str != NULL);
+ /* Assume the given string is already nul-terminated and in memory that
+ * will live as long as this node.
+ */
+ assert(str[n] == '\0');
+ this->str = str;
}
s_list::s_list()
@@ -36,22 +39,26 @@ s_list::s_list()
}
static void
-skip_whitespace(const char *& src)
+skip_whitespace(const char *&src, char *&symbol_buffer)
{
- src += strspn(src, " \v\t\r\n");
+ size_t n = strspn(src, " \v\t\r\n");
+ src += n;
+ symbol_buffer += n;
/* Also skip Scheme-style comments: semi-colon 'til end of line */
if (src[0] == ';') {
- src += strcspn(src, "\n");
- skip_whitespace(src);
+ n = strcspn(src, "\n");
+ src += n;
+ symbol_buffer += n;
+ skip_whitespace(src, symbol_buffer);
}
}
static s_expression *
-read_atom(void *ctx, const char *& src)
+read_atom(void *ctx, const char *&src, char *&symbol_buffer)
{
s_expression *expr = NULL;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
size_t n = strcspn(src, "( \v\t\r\n);");
if (n == 0)
@@ -70,44 +77,65 @@ read_atom(void *ctx, const char *& src)
expr = new(ctx) s_int(i);
} else {
// Not a number; return a symbol.
- expr = new(ctx) s_symbol(src, n);
+ symbol_buffer[n] = '\0';
+ expr = new(ctx) s_symbol(symbol_buffer, n);
}
src += n;
+ symbol_buffer += n;
return expr;
}
-s_expression *
-s_expression::read_expression(void *ctx, const char *&src)
+static s_expression *
+__read_expression(void *ctx, const char *&src, char *&symbol_buffer)
{
- assert(src != NULL);
-
- s_expression *atom = read_atom(ctx, src);
+ s_expression *atom = read_atom(ctx, src, symbol_buffer);
if (atom != NULL)
return atom;
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] == '(') {
++src;
+ ++symbol_buffer;
s_list *list = new(ctx) s_list;
s_expression *expr;
- while ((expr = read_expression(ctx, src)) != NULL) {
+ while ((expr = __read_expression(ctx, src, symbol_buffer)) != NULL) {
list->subexpressions.push_tail(expr);
}
- skip_whitespace(src);
+ skip_whitespace(src, symbol_buffer);
if (src[0] != ')') {
printf("Unclosed expression (check your parenthesis).\n");
return NULL;
}
++src;
+ ++symbol_buffer;
return list;
}
return NULL;
}
+s_expression *
+s_expression::read_expression(void *ctx, const char *&src)
+{
+ assert(src != NULL);
+
+ /* When we encounter a Symbol, we need to save a nul-terminated copy of
+ * the string. However, ralloc_strndup'ing every individual Symbol is
+ * extremely expensive. We could avoid this by simply overwriting the
+ * next character (guaranteed to be whitespace, parens, or semicolon) with
+ * a nul-byte. But overwriting non-whitespace would mess up parsing.
+ *
+ * So, just copy the whole buffer ahead of time. Walk both, leaving the
+ * original source string unmodified, and altering the copy to contain the
+ * necessary nul-bytes whenever we encounter a symbol.
+ */
+ char *symbol_buffer = ralloc_strdup(ctx, src);
+ return __read_expression(ctx, src, symbol_buffer);
+}
+
void s_int::print()
{
printf("%d", this->val);
diff --git a/src/glsl/s_expression.h b/src/glsl/s_expression.h
index c9dc676b319..642af19b439 100644
--- a/src/glsl/s_expression.h
+++ b/src/glsl/s_expression.h
@@ -129,7 +129,7 @@ public:
void print();
private:
- char *str;
+ const char *str;
};
/* Lists of expressions: (expr1 ... exprN) */
diff --git a/src/mesa/drivers/common/meta.c b/src/mesa/drivers/common/meta.c
index 706239c7736..fa78674e4eb 100644
--- a/src/mesa/drivers/common/meta.c
+++ b/src/mesa/drivers/common/meta.c
@@ -62,6 +62,7 @@
#include "main/teximage.h"
#include "main/texparam.h"
#include "main/texstate.h"
+#include "main/uniforms.h"
#include "main/varray.h"
#include "main/viewport.h"
#include "program/program.h"
@@ -235,6 +236,8 @@ struct clear_state
{
GLuint ArrayObj;
GLuint VBO;
+ GLuint ShaderProg;
+ GLint ColorLocation;
};
@@ -1589,10 +1592,165 @@ _mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers)
_mesa_meta_end(ctx);
}
+static void
+meta_glsl_clear_init(struct gl_context *ctx, struct clear_state *clear)
+{
+ const char *vs_source =
+ "attribute vec4 position;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = position;\n"
+ "}\n";
+ const char *fs_source =
+ "uniform vec4 color;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = color;\n"
+ "}\n";
+ GLuint vs, fs;
+
+ if (clear->ArrayObj != 0)
+ return;
+
+ /* create vertex array object */
+ _mesa_GenVertexArrays(1, &clear->ArrayObj);
+ _mesa_BindVertexArray(clear->ArrayObj);
+
+ /* create vertex array buffer */
+ _mesa_GenBuffersARB(1, &clear->VBO);
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO);
+
+ /* setup vertex arrays */
+ _mesa_VertexAttribPointerARB(0, 3, GL_FLOAT, GL_FALSE, 0, (void *)0);
+ _mesa_EnableVertexAttribArrayARB(0);
+
+ vs = _mesa_CreateShaderObjectARB(GL_VERTEX_SHADER);
+ _mesa_ShaderSourceARB(vs, 1, &vs_source, NULL);
+ _mesa_CompileShaderARB(vs);
+
+ fs = _mesa_CreateShaderObjectARB(GL_FRAGMENT_SHADER);
+ _mesa_ShaderSourceARB(fs, 1, &fs_source, NULL);
+ _mesa_CompileShaderARB(fs);
+
+ clear->ShaderProg = _mesa_CreateProgramObjectARB();
+ _mesa_AttachShader(clear->ShaderProg, fs);
+ _mesa_AttachShader(clear->ShaderProg, vs);
+ _mesa_BindAttribLocationARB(clear->ShaderProg, 0, "position");
+ _mesa_LinkProgramARB(clear->ShaderProg);
+
+ clear->ColorLocation = _mesa_GetUniformLocationARB(clear->ShaderProg,
+ "color");
+}
+
+/**
+ * Meta implementation of ctx->Driver.Clear() in terms of polygon rendering.
+ */
+void
+_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers)
+{
+ struct clear_state *clear = &ctx->Meta->Clear;
+ GLbitfield metaSave;
+ const GLuint stencilMax = (1 << ctx->DrawBuffer->Visual.stencilBits) - 1;
+ struct gl_framebuffer *fb = ctx->DrawBuffer;
+ const float x0 = ((float)fb->_Xmin / fb->Width) * 2.0f - 1.0f;
+ const float y0 = ((float)fb->_Ymin / fb->Height) * 2.0f - 1.0f;
+ const float x1 = ((float)fb->_Xmax / fb->Width) * 2.0f - 1.0f;
+ const float y1 = ((float)fb->_Ymax / fb->Height) * 2.0f - 1.0f;
+ const float z = -invert_z(ctx->Depth.Clear);
+ struct vertex {
+ GLfloat x, y, z;
+ } verts[4];
+
+ metaSave = (META_ALPHA_TEST |
+ META_BLEND |
+ META_DEPTH_TEST |
+ META_RASTERIZATION |
+ META_SHADER |
+ META_STENCIL_TEST |
+ META_VERTEX |
+ META_VIEWPORT |
+ META_CLAMP_FRAGMENT_COLOR);
+
+ if (!(buffers & BUFFER_BITS_COLOR)) {
+ /* We'll use colormask to disable color writes. Otherwise,
+ * respect color mask
+ */
+ metaSave |= META_COLOR_MASK;
+ }
+
+ _mesa_meta_begin(ctx, metaSave);
+
+ meta_glsl_clear_init(ctx, clear);
+
+ _mesa_UseProgramObjectARB(clear->ShaderProg);
+ _mesa_Uniform4fvARB(clear->ColorLocation, 1,
+ ctx->Color.ClearColorUnclamped);
+
+ _mesa_BindVertexArray(clear->ArrayObj);
+ _mesa_BindBufferARB(GL_ARRAY_BUFFER_ARB, clear->VBO);
+
+ /* GL_COLOR_BUFFER_BIT */
+ if (buffers & BUFFER_BITS_COLOR) {
+ /* leave colormask, glDrawBuffer state as-is */
+
+ /* Clears never have the color clamped. */
+ _mesa_ClampColorARB(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE);
+ }
+ else {
+ ASSERT(metaSave & META_COLOR_MASK);
+ _mesa_ColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+
+ /* GL_DEPTH_BUFFER_BIT */
+ if (buffers & BUFFER_BIT_DEPTH) {
+ _mesa_set_enable(ctx, GL_DEPTH_TEST, GL_TRUE);
+ _mesa_DepthFunc(GL_ALWAYS);
+ _mesa_DepthMask(GL_TRUE);
+ }
+ else {
+ assert(!ctx->Depth.Test);
+ }
+
+ /* GL_STENCIL_BUFFER_BIT */
+ if (buffers & BUFFER_BIT_STENCIL) {
+ _mesa_set_enable(ctx, GL_STENCIL_TEST, GL_TRUE);
+ _mesa_StencilOpSeparate(GL_FRONT_AND_BACK,
+ GL_REPLACE, GL_REPLACE, GL_REPLACE);
+ _mesa_StencilFuncSeparate(GL_FRONT_AND_BACK, GL_ALWAYS,
+ ctx->Stencil.Clear & stencilMax,
+ ctx->Stencil.WriteMask[0]);
+ }
+ else {
+ assert(!ctx->Stencil.Enabled);
+ }
+
+ /* vertex positions */
+ verts[0].x = x0;
+ verts[0].y = y0;
+ verts[0].z = z;
+ verts[1].x = x1;
+ verts[1].y = y0;
+ verts[1].z = z;
+ verts[2].x = x1;
+ verts[2].y = y1;
+ verts[2].z = z;
+ verts[3].x = x0;
+ verts[3].y = y1;
+ verts[3].z = z;
+
+ /* upload new vertex data */
+ _mesa_BufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(verts), verts,
+ GL_DYNAMIC_DRAW_ARB);
+
+ /* draw quad */
+ _mesa_DrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ _mesa_meta_end(ctx);
+}
/**
* Meta implementation of ctx->Driver.CopyPixels() in terms
- * of texture mapping and polygon rendering.
+ * of texture mapping and polygon rendering and GLSL shaders.
*/
void
_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcX, GLint srcY,
diff --git a/src/mesa/drivers/common/meta.h b/src/mesa/drivers/common/meta.h
index 7190dee768a..95b4b5579c8 100644
--- a/src/mesa/drivers/common/meta.h
+++ b/src/mesa/drivers/common/meta.h
@@ -43,6 +43,9 @@ extern void
_mesa_meta_Clear(struct gl_context *ctx, GLbitfield buffers);
extern void
+_mesa_meta_glsl_Clear(struct gl_context *ctx, GLbitfield buffers);
+
+extern void
_mesa_meta_CopyPixels(struct gl_context *ctx, GLint srcx, GLint srcy,
GLsizei width, GLsizei height,
GLint dstx, GLint dsty, GLenum type);
diff --git a/src/mesa/drivers/dri/i965/gen6_vs_state.c b/src/mesa/drivers/dri/i965/gen6_vs_state.c
index fb4cdbaadf9..e70454416bf 100644
--- a/src/mesa/drivers/dri/i965/gen6_vs_state.c
+++ b/src/mesa/drivers/dri/i965/gen6_vs_state.c
@@ -160,6 +160,32 @@ upload_vs_state(struct brw_context *brw)
GEN6_VS_STATISTICS_ENABLE |
GEN6_VS_ENABLE);
ADVANCE_BATCH();
+
+ /* Based on my reading of the simulator, the VS constants don't get
+ * pulled into the VS FF unit until an appropriate pipeline flush
+ * happens, and instead the 3DSTATE_CONSTANT_VS packet just adds
+ * references to them into a little FIFO. The flushes are common,
+ * but don't reliably happen between this and a 3DPRIMITIVE, causing
+ * the primitive to use the wrong constants. Then the FIFO
+ * containing the constant setup gets added to again on the next
+ * constants change, and eventually when a flush does happen the
+ * unit is overwhelmed by constant changes and dies.
+ *
+ * To avoid this, send a PIPE_CONTROL down the line that will
+ * update the unit immediately loading the constants. The flush
+ * type bits here were those set by the STATE_BASE_ADDRESS whose
+ * move in a82a43e8d99e1715dd11c9c091b5ab734079b6a6 triggered the
+ * bug reports that led to this workaround, and may be more than
+ * what is strictly required to avoid the issue.
+ */
+ BEGIN_BATCH(4);
+ OUT_BATCH(_3DSTATE_PIPE_CONTROL);
+ OUT_BATCH(PIPE_CONTROL_DEPTH_STALL |
+ PIPE_CONTROL_INSTRUCTION_FLUSH |
+ PIPE_CONTROL_STATE_CACHE_INVALIDATE);
+ OUT_BATCH(0); /* address */
+ OUT_BATCH(0); /* write data */
+ ADVANCE_BATCH();
}
const struct brw_tracked_state gen6_vs_state = {
diff --git a/src/mesa/drivers/dri/intel/intel_batchbuffer.c b/src/mesa/drivers/dri/intel/intel_batchbuffer.c
index b61a2ffef19..97cc219ce6d 100644
--- a/src/mesa/drivers/dri/intel/intel_batchbuffer.c
+++ b/src/mesa/drivers/dri/intel/intel_batchbuffer.c
@@ -308,12 +308,29 @@ emit:
* [Dev-SNB{W/A}]: Before a PIPE_CONTROL with Write Cache Flush Enable
* =1, a PIPE_CONTROL with any non-zero post-sync-op is required.
*
- * XXX: There is also a workaround that would appear to apply to this
- * workaround, but it doesn't appear to be necessary so far:
+ * And the workaround for these two requires this workaround first:
*
- * Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
+ * [Dev-SNB{W/A}]: Pipe-control with CS-stall bit set must be sent
* BEFORE the pipe-control with a post-sync op and no write-cache
* flushes.
+ *
+ * And this last workaround is tricky because of the requirements on
+ * that bit. From section 1.4.7.2.3 "Stall" of the Sandy Bridge PRM
+ * volume 2 part 1:
+ *
+ * "1 of the following must also be set:
+ * - Render Target Cache Flush Enable ([12] of DW1)
+ * - Depth Cache Flush Enable ([0] of DW1)
+ * - Stall at Pixel Scoreboard ([1] of DW1)
+ * - Depth Stall ([13] of DW1)
+ * - Post-Sync Operation ([13] of DW1)
+ * - Notify Enable ([8] of DW1)"
+ *
+ * The cache flushes require the workaround flush that triggered this
+ * one, so we can't use it. Depth stall would trigger the same.
+ * Post-sync nonzero is what triggered this second workaround, so we
+ * can't use that one either. Notify enable is IRQs, which aren't
+ * really our business. That leaves only stall at scoreboard.
*/
void
intel_emit_post_sync_nonzero_flush(struct intel_context *intel)
@@ -323,9 +340,17 @@ intel_emit_post_sync_nonzero_flush(struct intel_context *intel)
BEGIN_BATCH(4);
OUT_BATCH(_3DSTATE_PIPE_CONTROL);
+ OUT_BATCH(PIPE_CONTROL_CS_STALL |
+ PIPE_CONTROL_STALL_AT_SCOREBOARD);
+ OUT_BATCH(0); /* address */
+ OUT_BATCH(0); /* write data */
+ ADVANCE_BATCH();
+
+ BEGIN_BATCH(4);
+ OUT_BATCH(_3DSTATE_PIPE_CONTROL);
OUT_BATCH(PIPE_CONTROL_WRITE_IMMEDIATE);
OUT_RELOC(intel->batch.workaround_bo,
- I915_GEM_DOMAIN_GTT, I915_GEM_DOMAIN_GTT, 0);
+ I915_GEM_DOMAIN_INSTRUCTION, I915_GEM_DOMAIN_INSTRUCTION, 0);
OUT_BATCH(0); /* write data */
ADVANCE_BATCH();
diff --git a/src/mesa/drivers/dri/intel/intel_clear.c b/src/mesa/drivers/dri/intel/intel_clear.c
index 5ab98734cfc..81c062fba53 100644
--- a/src/mesa/drivers/dri/intel/intel_clear.c
+++ b/src/mesa/drivers/dri/intel/intel_clear.c
@@ -188,7 +188,10 @@ intelClear(struct gl_context *ctx, GLbitfield mask)
if (tri_mask) {
debug_mask("tri", tri_mask);
- _mesa_meta_Clear(&intel->ctx, tri_mask);
+ if (ctx->Extensions.ARB_fragment_shader)
+ _mesa_meta_glsl_Clear(&intel->ctx, tri_mask);
+ else
+ _mesa_meta_Clear(&intel->ctx, tri_mask);
}
}
diff --git a/src/mesa/drivers/dri/intel/intel_reg.h b/src/mesa/drivers/dri/intel/intel_reg.h
index 5aa629150cf..a98a669af21 100644
--- a/src/mesa/drivers/dri/intel/intel_reg.h
+++ b/src/mesa/drivers/dri/intel/intel_reg.h
@@ -75,6 +75,7 @@
#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1 << 4)
#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1 << 3)
#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1 << 2)
+#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1 << 1)
#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1 << 0)
#define PIPE_CONTROL_PPGTT_WRITE (0 << 2)
#define PIPE_CONTROL_GLOBAL_GTT_WRITE (1 << 2)
diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c
index 84969360d92..82eb7fb718d 100644
--- a/src/mesa/main/fbobject.c
+++ b/src/mesa/main/fbobject.c
@@ -2134,10 +2134,14 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
{
const struct gl_renderbuffer_attachment *att;
struct gl_framebuffer *buffer;
+ GLenum err;
GET_CURRENT_CONTEXT(ctx);
ASSERT_OUTSIDE_BEGIN_END(ctx);
+ /* The error differs in GL andd GLES. */
+ err = ctx->API == API_OPENGL ? GL_INVALID_OPERATION : GL_INVALID_ENUM;
+
buffer = get_framebuffer_target(ctx, target);
if (!buffer) {
_mesa_error(ctx, GL_INVALID_ENUM,
@@ -2188,7 +2192,12 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
}
else {
assert(att->Type == GL_NONE);
- *params = 0;
+ if (ctx->API == API_OPENGL) {
+ *params = 0;
+ } else {
+ _mesa_error(ctx, GL_INVALID_ENUM,
+ "glGetFramebufferAttachmentParameterivEXT(pname)");
+ }
}
return;
case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_EXT:
@@ -2196,7 +2205,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
*params = att->TextureLevel;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2214,7 +2223,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
}
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2232,7 +2241,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
}
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2246,7 +2255,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2267,7 +2276,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
return;
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else {
@@ -2301,7 +2310,7 @@ _mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Type == GL_NONE) {
- _mesa_error(ctx, GL_INVALID_OPERATION,
+ _mesa_error(ctx, err,
"glGetFramebufferAttachmentParameterivEXT(pname)");
}
else if (att->Texture) {