summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/mesa/drivers/dri/i965/Makefile.sources1
-rw-r--r--src/mesa/drivers/dri/i965/brw_blorp.cpp32
-rw-r--r--src/mesa/drivers/dri/i965/brw_blorp.h136
-rw-r--r--src/mesa/drivers/dri/i965/brw_blorp_blit.cpp863
-rw-r--r--src/mesa/drivers/dri/i965/brw_context.h8
-rw-r--r--src/mesa/drivers/dri/i965/gen6_blorp.cpp397
-rw-r--r--src/mesa/drivers/dri/i965/gen7_blorp.cpp311
-rw-r--r--src/mesa/drivers/dri/intel/intel_fbo.c9
8 files changed, 1730 insertions, 27 deletions
diff --git a/src/mesa/drivers/dri/i965/Makefile.sources b/src/mesa/drivers/dri/i965/Makefile.sources
index 41ce34b2e9c..182b432ed45 100644
--- a/src/mesa/drivers/dri/i965/Makefile.sources
+++ b/src/mesa/drivers/dri/i965/Makefile.sources
@@ -111,6 +111,7 @@ i965_C_FILES = \
i965_CXX_FILES = \
brw_blorp.cpp \
+ brw_blorp_blit.cpp \
brw_cubemap_normalize.cpp \
brw_fs.cpp \
brw_fs_cfg.cpp \
diff --git a/src/mesa/drivers/dri/i965/brw_blorp.cpp b/src/mesa/drivers/dri/i965/brw_blorp.cpp
index 95f039f63db..762d7350632 100644
--- a/src/mesa/drivers/dri/i965/brw_blorp.cpp
+++ b/src/mesa/drivers/dri/i965/brw_blorp.cpp
@@ -35,6 +35,11 @@ brw_blorp_mip_info::brw_blorp_mip_info()
{
}
+brw_blorp_surface_info::brw_blorp_surface_info()
+ : map_stencil_as_y_tiled(false)
+{
+}
+
void
brw_blorp_mip_info::set(struct intel_mipmap_tree *mt,
unsigned int level, unsigned int layer)
@@ -47,6 +52,23 @@ brw_blorp_mip_info::set(struct intel_mipmap_tree *mt,
}
void
+brw_blorp_surface_info::set(struct intel_mipmap_tree *mt,
+ unsigned int level, unsigned int layer)
+{
+ brw_blorp_mip_info::set(mt, level, layer);
+
+ if (mt->format == MESA_FORMAT_S8) {
+ /* The miptree is a W-tiled stencil buffer. Surface states can't be set
+ * up for W tiling, so we'll need to use Y tiling and have the WM
+ * program swizzle the coordinates.
+ */
+ this->map_stencil_as_y_tiled = true;
+ } else {
+ this->map_stencil_as_y_tiled = false;
+ }
+}
+
+void
brw_blorp_mip_info::get_draw_offsets(uint32_t *draw_x, uint32_t *draw_y) const
{
/* Construct a dummy renderbuffer just to extract tile offsets. */
@@ -65,7 +87,8 @@ brw_blorp_params::brw_blorp_params()
x1(0),
y1(0),
depth_format(0),
- hiz_op(GEN6_HIZ_OP_NONE)
+ hiz_op(GEN6_HIZ_OP_NONE),
+ use_wm_prog(false)
{
}
@@ -106,3 +129,10 @@ brw_hiz_op_params::brw_hiz_op_params(struct intel_mipmap_tree *mt,
default: assert(0); break;
}
}
+
+uint32_t
+brw_hiz_op_params::get_wm_prog(struct brw_context *brw,
+ brw_blorp_prog_data **prog_data) const
+{
+ return 0;
+}
diff --git a/src/mesa/drivers/dri/i965/brw_blorp.h b/src/mesa/drivers/dri/i965/brw_blorp.h
index c1c8334f6b5..b6b659dbdae 100644
--- a/src/mesa/drivers/dri/i965/brw_blorp.h
+++ b/src/mesa/drivers/dri/i965/brw_blorp.h
@@ -44,13 +44,24 @@ enum gen6_hiz_op {
GEN6_HIZ_OP_NONE,
};
+
+/**
+ * Binding table indices used by BLORP.
+ */
+enum {
+ BRW_BLORP_TEXTURE_BINDING_TABLE_INDEX,
+ BRW_BLORP_RENDERBUFFER_BINDING_TABLE_INDEX,
+ BRW_BLORP_NUM_BINDING_TABLE_ENTRIES
+};
+
+
class brw_blorp_mip_info
{
public:
brw_blorp_mip_info();
- void set(struct intel_mipmap_tree *mt,
- unsigned int level, unsigned int layer);
+ virtual void set(struct intel_mipmap_tree *mt,
+ unsigned int level, unsigned int layer);
void get_draw_offsets(uint32_t *draw_x, uint32_t *draw_y) const;
void get_miplevel_dims(uint32_t *width, uint32_t *height) const
@@ -64,11 +75,71 @@ public:
unsigned int layer;
};
+class brw_blorp_surface_info : public brw_blorp_mip_info
+{
+public:
+ brw_blorp_surface_info();
+
+ virtual void set(struct intel_mipmap_tree *mt,
+ unsigned int level, unsigned int layer);
+
+ /* Setting this flag indicates that the buffer's contents are W-tiled
+ * stencil data, but the surface state should be set up for Y tiled
+ * MESA_FORMAT_R8 data (this is necessary because surface states don't
+ * support W tiling).
+ *
+ * Since W tiles are 64 pixels wide by 64 pixels high, whereas Y tiles of
+ * MESA_FORMAT_R8 data are 128 pixels wide by 32 pixels high, the width and
+ * pitch stored in the surface state will be multiplied by 2, and the
+ * height will be halved. Also, since W and Y tiles store their data in a
+ * different order, the width and height will be rounded up to a multiple
+ * of the tile size, to ensure that the WM program can access the full
+ * width and height of the buffer.
+ */
+ bool map_stencil_as_y_tiled;
+};
+
+
+struct brw_blorp_coord_transform_params
+{
+ void setup(GLuint src0, GLuint dst0, GLuint dst1,
+ bool mirror);
+
+ int16_t multiplier;
+ int16_t offset;
+};
+
+
+struct brw_blorp_wm_push_constants
+{
+ uint16_t dst_x0;
+ uint16_t dst_x1;
+ uint16_t dst_y0;
+ uint16_t dst_y1;
+ brw_blorp_coord_transform_params x_transform;
+ brw_blorp_coord_transform_params y_transform;
+
+ /* Pad out to an integral number of registers */
+ uint16_t pad[8];
+};
+
+/* Every 32 bytes of push constant data constitutes one GEN register. */
+const unsigned int BRW_BLORP_NUM_PUSH_CONST_REGS =
+ sizeof(brw_blorp_wm_push_constants) / 32;
+
+struct brw_blorp_prog_data
+{
+ unsigned int first_curbe_grf;
+};
+
class brw_blorp_params
{
public:
brw_blorp_params();
+ virtual uint32_t get_wm_prog(struct brw_context *brw,
+ brw_blorp_prog_data **prog_data) const = 0;
+
void exec(struct intel_context *intel) const;
uint32_t x0;
@@ -77,7 +148,11 @@ public:
uint32_t y1;
brw_blorp_mip_info depth;
uint32_t depth_format;
+ brw_blorp_surface_info src;
+ brw_blorp_surface_info dst;
enum gen6_hiz_op hiz_op;
+ bool use_wm_prog;
+ brw_blorp_wm_push_constants wm_push_consts;
};
/**
@@ -95,6 +170,45 @@ public:
brw_hiz_op_params(struct intel_mipmap_tree *mt,
unsigned int level, unsigned int layer,
gen6_hiz_op op);
+
+ virtual uint32_t get_wm_prog(struct brw_context *brw,
+ brw_blorp_prog_data **prog_data) const;
+};
+
+struct brw_blorp_blit_prog_key
+{
+ /* True if the source image is W tiled. If true, the surface state for the
+ * source image must be configured as Y tiled.
+ */
+ bool src_tiled_w;
+
+ /* True if the destination image is W tiled. If true, the surface state
+ * for the render target must be configured as Y tiled.
+ */
+ bool dst_tiled_w;
+
+ /* True if the rectangle being sent through the rendering pipeline might be
+ * larger than the destination rectangle, so the WM program should kill any
+ * pixels that are outside the destination rectangle.
+ */
+ bool use_kill;
+};
+
+class brw_blorp_blit_params : public brw_blorp_params
+{
+public:
+ brw_blorp_blit_params(struct intel_mipmap_tree *src_mt,
+ struct intel_mipmap_tree *dst_mt,
+ GLuint src_x0, GLuint src_y0,
+ GLuint dst_x0, GLuint dst_y0,
+ GLuint width, GLuint height,
+ bool mirror_x, bool mirror_y);
+
+ virtual uint32_t get_wm_prog(struct brw_context *brw,
+ brw_blorp_prog_data **prog_data) const;
+
+private:
+ brw_blorp_blit_prog_key wm_prog_key;
};
/**
@@ -119,11 +233,29 @@ void
gen6_blorp_emit_vertices(struct brw_context *brw,
const brw_blorp_params *params);
+uint32_t
+gen6_blorp_emit_blend_state(struct brw_context *brw,
+ const brw_blorp_params *params);
+
+uint32_t
+gen6_blorp_emit_cc_state(struct brw_context *brw,
+ const brw_blorp_params *params);
+
+uint32_t
+gen6_blorp_emit_wm_constants(struct brw_context *brw,
+ const brw_blorp_params *params);
+
void
gen6_blorp_emit_vs_disable(struct brw_context *brw,
const brw_blorp_params *params);
uint32_t
+gen6_blorp_emit_binding_table(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_surf_offset_renderbuffer,
+ uint32_t wm_surf_offset_texture);
+
+uint32_t
gen6_blorp_emit_depth_stencil_state(struct brw_context *brw,
const brw_blorp_params *params);
diff --git a/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
new file mode 100644
index 00000000000..cce5d1b560e
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_blorp_blit.cpp
@@ -0,0 +1,863 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#include "main/teximage.h"
+
+#include "glsl/ralloc.h"
+
+#include "intel_fbo.h"
+
+#include "brw_blorp.h"
+#include "brw_context.h"
+#include "brw_eu.h"
+#include "brw_state.h"
+
+
+/**
+ * Helper function for handling mirror image blits.
+ *
+ * If coord0 > coord1, swap them and invert the "mirror" boolean.
+ */
+static inline void
+fixup_mirroring(bool &mirror, GLint &coord0, GLint &coord1)
+{
+ if (coord0 > coord1) {
+ mirror = !mirror;
+ GLint tmp = coord0;
+ coord0 = coord1;
+ coord1 = tmp;
+ }
+}
+
+
+static bool
+try_blorp_blit(struct intel_context *intel,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLenum filter, GLbitfield buffer_bit)
+{
+ struct gl_context *ctx = &intel->ctx;
+
+ /* Sync up the state of window system buffers. We need to do this before
+ * we go looking for the buffers.
+ */
+ intel_prepare_render(intel);
+
+ /* Find buffers */
+ const struct gl_framebuffer *read_fb = ctx->ReadBuffer;
+ const struct gl_framebuffer *draw_fb = ctx->DrawBuffer;
+ struct gl_renderbuffer *src_rb;
+ struct gl_renderbuffer *dst_rb;
+ switch (buffer_bit) {
+ case GL_COLOR_BUFFER_BIT:
+ src_rb = read_fb->_ColorReadBuffer;
+ dst_rb =
+ draw_fb->Attachment[
+ draw_fb->_ColorDrawBufferIndexes[0]].Renderbuffer;
+ break;
+ case GL_DEPTH_BUFFER_BIT:
+ src_rb = read_fb->Attachment[BUFFER_DEPTH].Renderbuffer;
+ dst_rb = draw_fb->Attachment[BUFFER_DEPTH].Renderbuffer;
+ break;
+ case GL_STENCIL_BUFFER_BIT:
+ src_rb = read_fb->Attachment[BUFFER_STENCIL].Renderbuffer;
+ dst_rb = draw_fb->Attachment[BUFFER_STENCIL].Renderbuffer;
+ break;
+ default:
+ assert(false);
+ }
+
+ /* Validate source */
+ if (!src_rb) return false;
+ struct intel_renderbuffer *src_irb = intel_renderbuffer(src_rb);
+ struct intel_mipmap_tree *src_mt = src_irb->mt;
+ if (!src_mt) return false;
+ if (buffer_bit == GL_STENCIL_BUFFER_BIT && src_mt->stencil_mt)
+ src_mt = src_mt->stencil_mt;
+ switch (src_mt->format) {
+ case MESA_FORMAT_ARGB8888:
+ case MESA_FORMAT_X8_Z24:
+ case MESA_FORMAT_S8:
+ break; /* Supported */
+ default:
+ /* Unsupported format.
+ *
+ * TODO: need to support all formats that are allowed as multisample
+ * render targets.
+ */
+ return false;
+ }
+
+ /* Validate destination */
+ if (!dst_rb) return false;
+ struct intel_renderbuffer *dst_irb = intel_renderbuffer(dst_rb);
+ struct intel_mipmap_tree *dst_mt = dst_irb->mt;
+ if (!dst_mt) return false;
+ if (buffer_bit == GL_STENCIL_BUFFER_BIT && dst_mt->stencil_mt)
+ dst_mt = dst_mt->stencil_mt;
+ switch (dst_mt->format) {
+ case MESA_FORMAT_ARGB8888:
+ case MESA_FORMAT_X8_Z24:
+ case MESA_FORMAT_S8:
+ break; /* Supported */
+ default:
+ /* Unsupported format.
+ *
+ * TODO: need to support all formats that are allowed as multisample
+ * render targets.
+ */
+ return false;
+ }
+
+ /* Account for the fact that in the system framebuffer, the origin is at
+ * the lower left.
+ */
+ if (read_fb->Name == 0) {
+ srcY0 = read_fb->Height - srcY0;
+ srcY1 = read_fb->Height - srcY1;
+ }
+ if (draw_fb->Name == 0) {
+ dstY0 = draw_fb->Height - dstY0;
+ dstY1 = draw_fb->Height - dstY1;
+ }
+
+ /* Detect if the blit needs to be mirrored */
+ bool mirror_x = false, mirror_y = false;
+ fixup_mirroring(mirror_x, srcX0, srcX1);
+ fixup_mirroring(mirror_x, dstX0, dstX1);
+ fixup_mirroring(mirror_y, srcY0, srcY1);
+ fixup_mirroring(mirror_y, dstY0, dstY1);
+
+ /* Make sure width and height match */
+ GLsizei width = srcX1 - srcX0;
+ GLsizei height = srcY1 - srcY0;
+ if (width != dstX1 - dstX0) return false;
+ if (height != dstY1 - dstY0) return false;
+
+ /* Make sure width and height don't need to be clipped or scissored.
+ * TODO: support clipping and scissoring.
+ */
+ if (srcX0 < 0 || (GLuint) srcX1 > read_fb->Width) return false;
+ if (srcY0 < 0 || (GLuint) srcY1 > read_fb->Height) return false;
+ if (dstX0 < 0 || (GLuint) dstX1 > draw_fb->Width) return false;
+ if (dstY0 < 0 || (GLuint) dstY1 > draw_fb->Height) return false;
+ if (ctx->Scissor.Enabled) return false;
+
+ /* Get ready to blit. This includes depth resolving the src and dst
+ * buffers if necessary.
+ */
+ intel_renderbuffer_resolve_depth(intel, src_irb);
+ intel_renderbuffer_resolve_depth(intel, dst_irb);
+
+ /* Do the blit */
+ brw_blorp_blit_params params(src_mt, dst_mt,
+ srcX0, srcY0, dstX0, dstY0, dstX1, dstY1,
+ mirror_x, mirror_y);
+ params.exec(intel);
+
+ /* Mark the dst buffer as needing a HiZ resolve if necessary. */
+ intel_renderbuffer_set_needs_hiz_resolve(dst_irb);
+
+ return true;
+}
+
+GLbitfield
+brw_blorp_framebuffer(struct intel_context *intel,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter)
+{
+ /* BLORP is only supported on Gen6. TODO: implement on Gen7. */
+ if (intel->gen != 6)
+ return mask;
+
+ static GLbitfield buffer_bits[] = {
+ GL_COLOR_BUFFER_BIT,
+ GL_DEPTH_BUFFER_BIT,
+ GL_STENCIL_BUFFER_BIT,
+ };
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(buffer_bits); ++i) {
+ if ((mask & buffer_bits[i]) &&
+ try_blorp_blit(intel,
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ filter, buffer_bits[i])) {
+ mask &= ~buffer_bits[i];
+ }
+ }
+
+ return mask;
+}
+
+/**
+ * Generator for WM programs used in BLORP blits.
+ *
+ * The bulk of the work done by the WM program is to wrap and unwrap the
+ * coordinate transformations used by the hardware to store surfaces in
+ * memory. The hardware transforms a pixel location (X, Y) to a memory offset
+ * by the following formulas:
+ *
+ * offset = tile(tiling_format, X, Y)
+ * (X, Y) = detile(tiling_format, offset)
+ *
+ * For X tiling, tile() combines together the low-order bits of the X and Y
+ * coordinates in the pattern 0byyyxxxxxxxxx, creating 4k tiles that are 512
+ * bytes wide and 8 rows high:
+ *
+ * tile(x_tiled, X, Y) = A
+ * where A = tile_num << 12 | offset
+ * tile_num = (Y >> 3) * tile_pitch + (X' >> 9)
+ * offset = (Y & 0b111) << 9
+ * | (X & 0b111111111)
+ * X' = X * cpp
+ * detile(x_tiled, A) = (X, Y)
+ * where X = X' / cpp
+ * Y = (tile_num / tile_pitch) << 3
+ * | (A & 0b111000000000) >> 9
+ * X' = (tile_num % tile_pitch) << 9
+ * | (A & 0b111111111)
+ *
+ * (In all tiling formulas, cpp is the number of bytes occupied by a single
+ * pixel ("chars per pixel"), and tile_pitch is the number of 4k tiles
+ * required to fill the width of the surface).
+ *
+ * For Y tiling, tile() combines together the low-order bits of the X and Y
+ * coordinates in the pattern 0bxxxyyyyyxxxx, creating 4k tiles that are 128
+ * bytes wide and 32 rows high:
+ *
+ * tile(y_tiled, X, Y) = A
+ * where A = tile_num << 12 | offset
+ * tile_num = (Y >> 5) * tile_pitch + (X' >> 7)
+ * offset = (X' & 0b1110000) << 5
+ * | (Y' & 0b11111) << 4
+ * | (X' & 0b1111)
+ * X' = X * cpp
+ * detile(y_tiled, A) = (X, Y)
+ * where X = X' / cpp
+ * Y = (tile_num / tile_pitch) << 5
+ * | (A & 0b111110000) >> 4
+ * X' = (tile_num % tile_pitch) << 7
+ * | (A & 0b111000000000) >> 5
+ * | (A & 0b1111)
+ *
+ * For W tiling, tile() combines together the low-order bits of the X and Y
+ * coordinates in the pattern 0bxxxyyyyxyxyx, creating 4k tiles that are 64
+ * bytes wide and 64 rows high (note that W tiling is only used for stencil
+ * buffers, which always have cpp = 1):
+ *
+ * tile(w_tiled, X, Y) = A
+ * where A = tile_num << 12 | offset
+ * tile_num = (Y >> 6) * tile_pitch + (X' >> 6)
+ * offset = (X' & 0b111000) << 6
+ * | (Y & 0b111100) << 3
+ * | (X' & 0b100) << 2
+ * | (Y & 0b10) << 2
+ * | (X' & 0b10) << 1
+ * | (Y & 0b1) << 1
+ * | (X' & 0b1)
+ * X' = X * cpp = X
+ * detile(w_tiled, A) = (X, Y)
+ * where X = X' / cpp = X'
+ * Y = (tile_num / tile_pitch) << 6
+ * | (A & 0b111100000) >> 3
+ * | (A & 0b1000) >> 2
+ * | (A & 0b10) >> 1
+ * X' = (tile_num % tile_pitch) << 6
+ * | (A & 0b111000000000) >> 6
+ * | (A & 0b10000) >> 2
+ * | (A & 0b100) >> 1
+ * | (A & 0b1)
+ *
+ * Finally, for a non-tiled surface, tile() simply combines together the X and
+ * Y coordinates in the natural way:
+ *
+ * tile(untiled, X, Y) = A
+ * where A = Y * pitch + X'
+ * X' = X * cpp
+ * detile(untiled, A) = (X, Y)
+ * where X = X' / cpp
+ * Y = A / pitch
+ * X' = A % pitch
+ *
+ * (In these formulas, pitch is the number of bytes occupied by a single row
+ * of pixels).
+ */
+class brw_blorp_blit_program
+{
+public:
+ brw_blorp_blit_program(struct brw_context *brw,
+ const brw_blorp_blit_prog_key *key);
+ ~brw_blorp_blit_program();
+
+ const GLuint *compile(struct brw_context *brw, GLuint *program_size);
+
+ brw_blorp_prog_data prog_data;
+
+private:
+ void alloc_regs();
+ void alloc_push_const_regs(int base_reg);
+ void compute_frag_coords();
+ void translate_tiling(bool old_tiled_w, bool new_tiled_w);
+ void kill_if_outside_dst_rect();
+ void translate_dst_to_src();
+ void texel_fetch();
+ void texture_lookup(GLuint msg_type,
+ struct brw_reg mrf_u, struct brw_reg mrf_v);
+ void render_target_write();
+
+ void *mem_ctx;
+ struct brw_context *brw;
+ const brw_blorp_blit_prog_key *key;
+ struct brw_compile func;
+
+ /* Thread dispatch header */
+ struct brw_reg R0;
+
+ /* Pixel X/Y coordinates (always in R1). */
+ struct brw_reg R1;
+
+ /* Push constants */
+ struct brw_reg dst_x0;
+ struct brw_reg dst_x1;
+ struct brw_reg dst_y0;
+ struct brw_reg dst_y1;
+ struct {
+ struct brw_reg multiplier;
+ struct brw_reg offset;
+ } x_transform, y_transform;
+
+ /* Data returned from texture lookup (4 vec16's) */
+ struct brw_reg Rdata;
+
+ /* X coordinates. We have two of them so that we can perform coordinate
+ * transformations easily.
+ */
+ struct brw_reg x_coords[2];
+
+ /* Y coordinates. We have two of them so that we can perform coordinate
+ * transformations easily.
+ */
+ struct brw_reg y_coords[2];
+
+ /* Which element of x_coords and y_coords is currently in use.
+ */
+ int xy_coord_index;
+
+ /* Temporaries */
+ struct brw_reg t1;
+ struct brw_reg t2;
+
+ /* M2-3: u coordinate */
+ GLuint base_mrf;
+ struct brw_reg mrf_u_float;
+
+ /* M4-5: v coordinate */
+ struct brw_reg mrf_v_float;
+};
+
+brw_blorp_blit_program::brw_blorp_blit_program(
+ struct brw_context *brw,
+ const brw_blorp_blit_prog_key *key)
+ : mem_ctx(ralloc_context(NULL)),
+ brw(brw),
+ key(key)
+{
+ brw_init_compile(brw, &func, mem_ctx);
+}
+
+brw_blorp_blit_program::~brw_blorp_blit_program()
+{
+ ralloc_free(mem_ctx);
+}
+
+const GLuint *
+brw_blorp_blit_program::compile(struct brw_context *brw,
+ GLuint *program_size)
+{
+ brw_set_compression_control(&func, BRW_COMPRESSION_NONE);
+
+ alloc_regs();
+ compute_frag_coords();
+
+ /* Render target and texture hardware don't support W tiling. */
+ const bool rt_tiled_w = false;
+ const bool tex_tiled_w = false;
+
+ /* The address that data will be written to is determined by the
+ * coordinates supplied to the WM thread and the tiling of the render
+ * target, according to the formula:
+ *
+ * (X, Y) = detile(rt_tiling, offset)
+ *
+ * If the actual tiling of the destination surface is not the same as the
+ * configuration of the render target, then these coordinates are wrong and
+ * we have to adjust them to compensate for the difference.
+ */
+ if (rt_tiled_w != key->dst_tiled_w)
+ translate_tiling(rt_tiled_w, key->dst_tiled_w);
+
+ /* Now (X, Y) = detile(dst_tiling, offset).
+ *
+ * That is: X and Y now contain the true coordinates of the data that the
+ * WM thread should output.
+ *
+ * If we need to kill pixels that are outside the destination rectangle,
+ * now is the time to do it.
+ */
+
+ if (key->use_kill)
+ kill_if_outside_dst_rect();
+
+ /* Next, apply a translation to obtain coordinates in the source image. */
+ translate_dst_to_src();
+
+ /* X and Y are now the coordinates of the pixel in the source image that we
+ * want to texture from.
+ *
+ * The address that we want to fetch from is
+ * related to the X and Y values according to the formula:
+ *
+ * (X, Y) = detile(src_tiling, offset).
+ *
+ * If the actual tiling of the source surface is not the same as the
+ * configuration of the texture, then we need to adjust the coordinates to
+ * compensate for the difference.
+ */
+ if (tex_tiled_w != key->src_tiled_w)
+ translate_tiling(key->src_tiled_w, tex_tiled_w);
+
+ /* Now (X, Y) = detile(tex_tiling, offset).
+ *
+ * In other words: X and Y now contain values which, when passed to
+ * the texturing unit, will cause data to be read from the correct
+ * memory location. So we can fetch the texel now.
+ */
+ texel_fetch();
+
+ /* Finally, write the fetched value to the render target and terminate the
+ * thread.
+ */
+ render_target_write();
+ return brw_get_program(&func, program_size);
+}
+
+void
+brw_blorp_blit_program::alloc_push_const_regs(int base_reg)
+{
+#define CONST_LOC(name) offsetof(brw_blorp_wm_push_constants, name)
+#define ALLOC_REG(name) \
+ this->name = \
+ brw_uw1_reg(BRW_GENERAL_REGISTER_FILE, base_reg, CONST_LOC(name) / 2)
+
+ ALLOC_REG(dst_x0);
+ ALLOC_REG(dst_x1);
+ ALLOC_REG(dst_y0);
+ ALLOC_REG(dst_y1);
+ ALLOC_REG(x_transform.multiplier);
+ ALLOC_REG(x_transform.offset);
+ ALLOC_REG(y_transform.multiplier);
+ ALLOC_REG(y_transform.offset);
+#undef CONST_LOC
+#undef ALLOC_REG
+}
+
+void
+brw_blorp_blit_program::alloc_regs()
+{
+ int reg = 0;
+ this->R0 = retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW);
+ this->R1 = retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW);
+ prog_data.first_curbe_grf = reg;
+ alloc_push_const_regs(reg);
+ reg += BRW_BLORP_NUM_PUSH_CONST_REGS;
+ this->Rdata = vec16(brw_vec8_grf(reg, 0)); reg += 8;
+ for (int i = 0; i < 2; ++i) {
+ this->x_coords[i]
+ = vec16(retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW));
+ this->y_coords[i]
+ = vec16(retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW));
+ }
+ this->xy_coord_index = 0;
+ this->t1 = vec16(retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW));
+ this->t2 = vec16(retype(brw_vec8_grf(reg++, 0), BRW_REGISTER_TYPE_UW));
+
+ int mrf = 2;
+ this->base_mrf = mrf;
+ this->mrf_u_float = vec16(brw_message_reg(mrf)); mrf += 2;
+ this->mrf_v_float = vec16(brw_message_reg(mrf)); mrf += 2;
+}
+
+/* In the code that follows, X and Y can be used to quickly refer to the
+ * active elements of x_coords and y_coords, and Xp and Yp ("X prime" and "Y
+ * prime") to the inactive elements.
+ */
+#define X x_coords[xy_coord_index]
+#define Y y_coords[xy_coord_index]
+#define Xp x_coords[!xy_coord_index]
+#define Yp y_coords[!xy_coord_index]
+
+/* Quickly swap the roles of (X, Y) and (Xp, Yp). Saves us from having to do
+ * MOVs to transfor (Xp, Yp) to (X, Y) after a coordinate transformation.
+ */
+#define SWAP_XY_AND_XPYP() xy_coord_index = !xy_coord_index;
+
+/**
+ * Emit code to compute the X and Y coordinates of the pixels being rendered
+ * by this WM invocation.
+ *
+ * Assuming the render target is set up for Y tiling, these (X, Y) values are
+ * related to the address offset where outputs will be written by the formula:
+ *
+ * (X, Y, S) = decode_msaa(detile(offset)).
+ *
+ * (See brw_blorp_blit_program).
+ */
+void
+brw_blorp_blit_program::compute_frag_coords()
+{
+ /* R1.2[15:0] = X coordinate of upper left pixel of subspan 0 (pixel 0)
+ * R1.3[15:0] = X coordinate of upper left pixel of subspan 1 (pixel 4)
+ * R1.4[15:0] = X coordinate of upper left pixel of subspan 2 (pixel 8)
+ * R1.5[15:0] = X coordinate of upper left pixel of subspan 3 (pixel 12)
+ *
+ * Pixels within a subspan are laid out in this arrangement:
+ * 0 1
+ * 2 3
+ *
+ * So, to compute the coordinates of each pixel, we need to read every 2nd
+ * 16-bit value (vstride=2) from R1, starting at the 4th 16-bit value
+ * (suboffset=4), and duplicate each value 4 times (hstride=0, width=4).
+ * In other words, the data we want to access is R1.4<2;4,0>UW.
+ *
+ * Then, we need to add the repeating sequence (0, 1, 0, 1, ...) to the
+ * result, since pixels n+1 and n+3 are in the right half of the subspan.
+ */
+ brw_ADD(&func, X, stride(suboffset(R1, 4), 2, 4, 0), brw_imm_v(0x10101010));
+
+ /* Similarly, Y coordinates for subspans come from R1.2[31:16] through
+ * R1.5[31:16], so to get pixel Y coordinates we need to start at the 5th
+ * 16-bit value instead of the 4th (R1.5<2;4,0>UW instead of
+ * R1.4<2;4,0>UW).
+ *
+ * And we need to add the repeating sequence (0, 0, 1, 1, ...), since
+ * pixels n+2 and n+3 are in the bottom half of the subspan.
+ */
+ brw_ADD(&func, Y, stride(suboffset(R1, 5), 2, 4, 0), brw_imm_v(0x11001100));
+}
+
+/**
+ * Emit code to compensate for the difference between Y and W tiling.
+ *
+ * This code modifies the X and Y coordinates according to the formula:
+ *
+ * (X', Y') = detile(new_tiling, tile(old_tiling, X, Y))
+ *
+ * (See brw_blorp_blit_program).
+ *
+ * It can only translate between W and Y tiling, so new_tiling and old_tiling
+ * are booleans where true represents W tiling and false represents Y tiling.
+ */
+void
+brw_blorp_blit_program::translate_tiling(bool old_tiled_w, bool new_tiled_w)
+{
+ if (old_tiled_w == new_tiled_w)
+ return;
+
+ if (new_tiled_w) {
+ /* Given X and Y coordinates that describe an address using Y tiling,
+ * translate to the X and Y coordinates that describe the same address
+ * using W tiling.
+ *
+ * If we break down the low order bits of X and Y, using a
+ * single letter to represent each low-order bit:
+ *
+ * X = A << 7 | 0bBCDEFGH
+ * Y = J << 5 | 0bKLMNP (1)
+ *
+ * Then we can apply the Y tiling formula to see the memory offset being
+ * addressed:
+ *
+ * offset = (J * tile_pitch + A) << 12 | 0bBCDKLMNPEFGH (2)
+ *
+ * If we apply the W detiling formula to this memory location, that the
+ * corresponding X' and Y' coordinates are:
+ *
+ * X' = A << 6 | 0bBCDPFH (3)
+ * Y' = J << 6 | 0bKLMNEG
+ *
+ * Combining (1) and (3), we see that to transform (X, Y) to (X', Y'),
+ * we need to make the following computation:
+ *
+ * X' = (X & ~0b1011) >> 1 | (Y & 0b1) << 2 | X & 0b1 (4)
+ * Y' = (Y & ~0b1) << 1 | (X & 0b1000) >> 2 | (X & 0b10) >> 1
+ */
+ brw_AND(&func, t1, X, brw_imm_uw(0xfff4)); /* X & ~0b1011 */
+ brw_SHR(&func, t1, t1, brw_imm_uw(1)); /* (X & ~0b1011) >> 1 */
+ brw_AND(&func, t2, Y, brw_imm_uw(1)); /* Y & 0b1 */
+ brw_SHL(&func, t2, t2, brw_imm_uw(2)); /* (Y & 0b1) << 2 */
+ brw_OR(&func, t1, t1, t2); /* (X & ~0b1011) >> 1 | (Y & 0b1) << 2 */
+ brw_AND(&func, t2, X, brw_imm_uw(1)); /* X & 0b1 */
+ brw_OR(&func, Xp, t1, t2);
+ brw_AND(&func, t1, Y, brw_imm_uw(0xfffe)); /* Y & ~0b1 */
+ brw_SHL(&func, t1, t1, brw_imm_uw(1)); /* (Y & ~0b1) << 1 */
+ brw_AND(&func, t2, X, brw_imm_uw(8)); /* X & 0b1000 */
+ brw_SHR(&func, t2, t2, brw_imm_uw(2)); /* (X & 0b1000) >> 2 */
+ brw_OR(&func, t1, t1, t2); /* (Y & ~0b1) << 1 | (X & 0b1000) >> 2 */
+ brw_AND(&func, t2, X, brw_imm_uw(2)); /* X & 0b10 */
+ brw_SHR(&func, t2, t2, brw_imm_uw(1)); /* (X & 0b10) >> 1 */
+ brw_OR(&func, Yp, t1, t2);
+ SWAP_XY_AND_XPYP();
+ } else {
+ /* Applying the same logic as above, but in reverse, we obtain the
+ * formulas:
+ *
+ * X' = (X & ~0b101) << 1 | (Y & 0b10) << 2 | (Y & 0b1) << 1 | X & 0b1
+ * Y' = (Y & ~0b11) >> 1 | (X & 0b100) >> 2
+ */
+ brw_AND(&func, t1, X, brw_imm_uw(0xfffa)); /* X & ~0b101 */
+ brw_SHL(&func, t1, t1, brw_imm_uw(1)); /* (X & ~0b101) << 1 */
+ brw_AND(&func, t2, Y, brw_imm_uw(2)); /* Y & 0b10 */
+ brw_SHL(&func, t2, t2, brw_imm_uw(2)); /* (Y & 0b10) << 2 */
+ brw_OR(&func, t1, t1, t2); /* (X & ~0b101) << 1 | (Y & 0b10) << 2 */
+ brw_AND(&func, t2, Y, brw_imm_uw(1)); /* Y & 0b1 */
+ brw_SHL(&func, t2, t2, brw_imm_uw(1)); /* (Y & 0b1) << 1 */
+ brw_OR(&func, t1, t1, t2); /* (X & ~0b101) << 1 | (Y & 0b10) << 2
+ | (Y & 0b1) << 1 */
+ brw_AND(&func, t2, X, brw_imm_uw(1)); /* X & 0b1 */
+ brw_OR(&func, Xp, t1, t2);
+ brw_AND(&func, t1, Y, brw_imm_uw(0xfffc)); /* Y & ~0b11 */
+ brw_SHR(&func, t1, t1, brw_imm_uw(1)); /* (Y & ~0b11) >> 1 */
+ brw_AND(&func, t2, X, brw_imm_uw(4)); /* X & 0b100 */
+ brw_SHR(&func, t2, t2, brw_imm_uw(2)); /* (X & 0b100) >> 2 */
+ brw_OR(&func, Yp, t1, t2);
+ SWAP_XY_AND_XPYP();
+ }
+}
+
+/**
+ * Emit code that kills pixels whose X and Y coordinates are outside the
+ * boundary of the rectangle defined by the push constants (dst_x0, dst_y0,
+ * dst_x1, dst_y1).
+ */
+void
+brw_blorp_blit_program::kill_if_outside_dst_rect()
+{
+ struct brw_reg f0 = brw_flag_reg();
+ struct brw_reg g1 = retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UW);
+ struct brw_reg null16 = vec16(retype(brw_null_reg(), BRW_REGISTER_TYPE_UW));
+
+ brw_CMP(&func, null16, BRW_CONDITIONAL_GE, X, dst_x0);
+ brw_CMP(&func, null16, BRW_CONDITIONAL_GE, Y, dst_y0);
+ brw_CMP(&func, null16, BRW_CONDITIONAL_L, X, dst_x1);
+ brw_CMP(&func, null16, BRW_CONDITIONAL_L, Y, dst_y1);
+
+ brw_set_predicate_control(&func, BRW_PREDICATE_NONE);
+ brw_push_insn_state(&func);
+ brw_set_mask_control(&func, BRW_MASK_DISABLE);
+ brw_AND(&func, g1, f0, g1);
+ brw_pop_insn_state(&func);
+}
+
+/**
+ * Emit code to translate from destination (X, Y) coordinates to source (X, Y)
+ * coordinates.
+ */
+void
+brw_blorp_blit_program::translate_dst_to_src()
+{
+ brw_MUL(&func, Xp, X, x_transform.multiplier);
+ brw_MUL(&func, Yp, Y, y_transform.multiplier);
+ brw_ADD(&func, Xp, Xp, x_transform.offset);
+ brw_ADD(&func, Yp, Yp, y_transform.offset);
+ SWAP_XY_AND_XPYP();
+}
+
+/**
+ * Emit code to look up a value in the texture using the SAMPLE_LD message
+ * (which does a simple texel fetch).
+ */
+void
+brw_blorp_blit_program::texel_fetch()
+{
+ texture_lookup(GEN5_SAMPLER_MESSAGE_SAMPLE_LD,
+ retype(mrf_u_float, BRW_REGISTER_TYPE_UD),
+ retype(mrf_v_float, BRW_REGISTER_TYPE_UD));
+}
+
+void
+brw_blorp_blit_program::texture_lookup(GLuint msg_type,
+ struct brw_reg mrf_u,
+ struct brw_reg mrf_v)
+{
+ /* Expand X and Y coordinates from 16 bits to 32 bits. */
+ brw_MOV(&func, vec8(mrf_u), vec8(X));
+ brw_set_compression_control(&func, BRW_COMPRESSION_2NDHALF);
+ brw_MOV(&func, offset(vec8(mrf_u), 1), suboffset(vec8(X), 8));
+ brw_set_compression_control(&func, BRW_COMPRESSION_NONE);
+ brw_MOV(&func, vec8(mrf_v), vec8(Y));
+ brw_set_compression_control(&func, BRW_COMPRESSION_2NDHALF);
+ brw_MOV(&func, offset(vec8(mrf_v), 1), suboffset(vec8(Y), 8));
+ brw_set_compression_control(&func, BRW_COMPRESSION_NONE);
+
+ brw_SAMPLE(&func,
+ retype(Rdata, BRW_REGISTER_TYPE_UW) /* dest */,
+ base_mrf /* msg_reg_nr */,
+ vec8(mrf_u) /* src0 */,
+ BRW_BLORP_TEXTURE_BINDING_TABLE_INDEX,
+ 0 /* sampler -- ignored for SAMPLE_LD message */,
+ WRITEMASK_XYZW,
+ msg_type,
+ 8 /* response_length. TODO: should be smaller for non-RGBA formats? */,
+ 4 /* msg_length */,
+ 0 /* header_present */,
+ BRW_SAMPLER_SIMD_MODE_SIMD16,
+ BRW_SAMPLER_RETURN_FORMAT_FLOAT32);
+}
+
+#undef X
+#undef Y
+#undef U
+#undef V
+#undef S
+#undef SWAP_XY_AND_XPYP
+
+void
+brw_blorp_blit_program::render_target_write()
+{
+ struct brw_reg mrf_rt_write = vec16(brw_message_reg(base_mrf));
+ int mrf_offset = 0;
+
+ /* If we may have killed pixels, then we need to send R0 and R1 in a header
+ * so that the render target knows which pixels we killed.
+ */
+ bool use_header = key->use_kill;
+ if (use_header) {
+ /* Copy R0/1 to MRF */
+ brw_MOV(&func, retype(mrf_rt_write, BRW_REGISTER_TYPE_UD),
+ retype(R0, BRW_REGISTER_TYPE_UD));
+ mrf_offset += 2;
+ }
+
+ /* Copy texture data to MRFs */
+ for (int i = 0; i < 4; ++i) {
+ /* E.g. mov(16) m2.0<1>:f r2.0<8;8,1>:f { Align1, H1 } */
+ brw_MOV(&func, offset(mrf_rt_write, mrf_offset), offset(vec8(Rdata), 2*i));
+ mrf_offset += 2;
+ }
+
+ /* Now write to the render target and terminate the thread */
+ brw_fb_WRITE(&func,
+ 16 /* dispatch_width */,
+ base_mrf /* msg_reg_nr */,
+ mrf_rt_write /* src0 */,
+ BRW_BLORP_RENDERBUFFER_BINDING_TABLE_INDEX,
+ mrf_offset /* msg_length. TODO: Should be smaller for non-RGBA formats. */,
+ 0 /* response_length */,
+ true /* eot */,
+ use_header);
+}
+
+
+void
+brw_blorp_coord_transform_params::setup(GLuint src0, GLuint dst0, GLuint dst1,
+ bool mirror)
+{
+ if (!mirror) {
+ /* When not mirroring a coordinate (say, X), we need:
+ * x' - src_x0 = x - dst_x0
+ * Therefore:
+ * x' = 1*x + (src_x0 - dst_x0)
+ */
+ multiplier = 1;
+ offset = src0 - dst0;
+ } else {
+ /* When mirroring X we need:
+ * x' - src_x0 = dst_x1 - x - 1
+ * Therefore:
+ * x' = -1*x + (src_x0 + dst_x1 - 1)
+ */
+ multiplier = -1;
+ offset = src0 + dst1 - 1;
+ }
+}
+
+
+brw_blorp_blit_params::brw_blorp_blit_params(struct intel_mipmap_tree *src_mt,
+ struct intel_mipmap_tree *dst_mt,
+ GLuint src_x0, GLuint src_y0,
+ GLuint dst_x0, GLuint dst_y0,
+ GLuint dst_x1, GLuint dst_y1,
+ bool mirror_x, bool mirror_y)
+{
+ src.set(src_mt, 0, 0);
+ dst.set(dst_mt, 0, 0);
+
+ use_wm_prog = true;
+ memset(&wm_prog_key, 0, sizeof(wm_prog_key));
+
+ wm_prog_key.src_tiled_w = src.map_stencil_as_y_tiled;
+ wm_prog_key.dst_tiled_w = dst.map_stencil_as_y_tiled;
+ x0 = wm_push_consts.dst_x0 = dst_x0;
+ y0 = wm_push_consts.dst_y0 = dst_y0;
+ x1 = wm_push_consts.dst_x1 = dst_x1;
+ y1 = wm_push_consts.dst_y1 = dst_y1;
+ wm_push_consts.x_transform.setup(src_x0, dst_x0, dst_x1, mirror_x);
+ wm_push_consts.y_transform.setup(src_y0, dst_y0, dst_y1, mirror_y);
+
+ if (dst.map_stencil_as_y_tiled) {
+ /* We must modify the rectangle we send through the rendering pipeline,
+ * to account for the fact that we are mapping it as Y-tiled when it is
+ * in fact W-tiled. Y tiles have dimensions 128x32 whereas W tiles have
+ * dimensions 64x64. We must also align it to a multiple of the tile
+ * size, because the differences between W and Y tiling formats will
+ * mean that pixels are scrambled within the tile.
+ * TODO: what if this makes the coordinates too large?
+ */
+ x0 = (x0 * 2) & ~127;
+ y0 = (y0 / 2) & ~31;
+ x1 = ALIGN(x1 * 2, 128);
+ y1 = ALIGN(y1 / 2, 32);
+ wm_prog_key.use_kill = true;
+ }
+}
+
+uint32_t
+brw_blorp_blit_params::get_wm_prog(struct brw_context *brw,
+ brw_blorp_prog_data **prog_data) const
+{
+ uint32_t prog_offset;
+ if (!brw_search_cache(&brw->cache, BRW_BLORP_BLIT_PROG,
+ &this->wm_prog_key, sizeof(this->wm_prog_key),
+ &prog_offset, prog_data)) {
+ brw_blorp_blit_program prog(brw, &this->wm_prog_key);
+ GLuint program_size;
+ const GLuint *program = prog.compile(brw, &program_size);
+ brw_upload_cache(&brw->cache, BRW_BLORP_BLIT_PROG,
+ &this->wm_prog_key, sizeof(this->wm_prog_key),
+ program, program_size,
+ &prog.prog_data, sizeof(prog.prog_data),
+ &prog_offset, prog_data);
+ }
+ return prog_offset;
+}
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index 141fb658d71..8ffd208ef64 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -536,6 +536,7 @@ enum brw_cache_id {
BRW_CC_VP,
BRW_CC_UNIT,
BRW_WM_PROG,
+ BRW_BLORP_BLIT_PROG,
BRW_SAMPLER,
BRW_WM_UNIT,
BRW_SF_PROG,
@@ -1091,6 +1092,13 @@ void
gen7_end_transform_feedback(struct gl_context *ctx,
struct gl_transform_feedback_object *obj);
+/* brw_blorp_blit.cpp */
+GLbitfield
+brw_blorp_framebuffer(struct intel_context *intel,
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter);
+
/*======================================================================
diff --git a/src/mesa/drivers/dri/i965/gen6_blorp.cpp b/src/mesa/drivers/dri/i965/gen6_blorp.cpp
index 33a1035aff2..00aeda63e60 100644
--- a/src/mesa/drivers/dri/i965/gen6_blorp.cpp
+++ b/src/mesa/drivers/dri/i965/gen6_blorp.cpp
@@ -144,7 +144,12 @@ gen6_blorp_emit_batch_head(struct brw_context *brw,
OUT_RELOC(intel->batch.bo, (I915_GEM_DOMAIN_RENDER |
I915_GEM_DOMAIN_INSTRUCTION), 0, 1);
OUT_BATCH(1); /* IndirectObjectBaseAddress */
- OUT_BATCH(1); /* InstructionBaseAddress */
+ if (params->use_wm_prog) {
+ OUT_RELOC(brw->cache.bo, I915_GEM_DOMAIN_INSTRUCTION, 0,
+ 1); /* Instruction base address: shader kernels */
+ } else {
+ OUT_BATCH(1); /* InstructionBaseAddress */
+ }
OUT_BATCH(1); /* GeneralStateUpperBound */
OUT_BATCH(1); /* DynamicStateUpperBound */
OUT_BATCH(1); /* IndirectObjectUpperBound*/
@@ -290,6 +295,51 @@ gen6_blorp_emit_urb_config(struct brw_context *brw,
}
+/* BLEND_STATE */
+uint32_t
+gen6_blorp_emit_blend_state(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ uint32_t cc_blend_state_offset;
+
+ struct gen6_blend_state *blend = (struct gen6_blend_state *)
+ brw_state_batch(brw, AUB_TRACE_BLEND_STATE,
+ sizeof(struct gen6_blend_state), 64,
+ &cc_blend_state_offset);
+
+ memset(blend, 0, sizeof(*blend));
+
+ // TODO: handle other formats.
+ blend->blend1.pre_blend_clamp_enable = 1;
+ blend->blend1.post_blend_clamp_enable = 1;
+ blend->blend1.clamp_range = BRW_RENDERTARGET_CLAMPRANGE_FORMAT;
+
+ blend->blend1.write_disable_r = false;
+ blend->blend1.write_disable_g = false;
+ blend->blend1.write_disable_b = false;
+ blend->blend1.write_disable_a = false;
+
+ return cc_blend_state_offset;
+}
+
+
+/* CC_STATE */
+uint32_t
+gen6_blorp_emit_cc_state(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ uint32_t cc_state_offset;
+
+ struct gen6_color_calc_state *cc = (struct gen6_color_calc_state *)
+ brw_state_batch(brw, AUB_TRACE_CC_STATE,
+ sizeof(gen6_color_calc_state), 64,
+ &cc_state_offset);
+ memset(cc, 0, sizeof(*cc));
+
+ return cc_state_offset;
+}
+
+
/**
* \param out_offset is relative to
* CMD_STATE_BASE_ADDRESS.DynamicStateBaseAddress.
@@ -332,15 +382,202 @@ gen6_blorp_emit_depth_stencil_state(struct brw_context *brw,
static void
gen6_blorp_emit_cc_state_pointers(struct brw_context *brw,
const brw_blorp_params *params,
- uint32_t depthstencil_offset)
+ uint32_t cc_blend_state_offset,
+ uint32_t depthstencil_offset,
+ uint32_t cc_state_offset)
{
struct intel_context *intel = &brw->intel;
BEGIN_BATCH(4);
OUT_BATCH(_3DSTATE_CC_STATE_POINTERS << 16 | (4 - 2));
- OUT_BATCH(1); /* BLEND_STATE offset */
+ OUT_BATCH(cc_blend_state_offset | 1); /* BLEND_STATE offset */
OUT_BATCH(depthstencil_offset | 1); /* DEPTH_STENCIL_STATE offset */
- OUT_BATCH(1); /* COLOR_CALC_STATE offset */
+ OUT_BATCH(cc_state_offset | 1); /* COLOR_CALC_STATE offset */
+ ADVANCE_BATCH();
+}
+
+
+/* WM push constants */
+uint32_t
+gen6_blorp_emit_wm_constants(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ uint32_t wm_push_const_offset;
+
+ void *constants = brw_state_batch(brw, AUB_TRACE_WM_CONSTANTS,
+ sizeof(params->wm_push_consts),
+ 32, &wm_push_const_offset);
+ memcpy(constants, &params->wm_push_consts,
+ sizeof(params->wm_push_consts));
+
+ return wm_push_const_offset;
+}
+
+
+/* SURFACE_STATE for renderbuffer or texture surface (see
+ * brw_update_renderbuffer_surface and brw_update_texture_surface)
+ */
+static uint32_t
+gen6_blorp_emit_surface_state(struct brw_context *brw,
+ const brw_blorp_params *params,
+ const brw_blorp_surface_info *surface,
+ uint32_t read_domains, uint32_t write_domain)
+{
+ uint32_t wm_surf_offset;
+ uint32_t width, height;
+ surface->get_miplevel_dims(&width, &height);
+ if (surface->map_stencil_as_y_tiled) {
+ width *= 2;
+ height /= 2;
+ }
+ struct intel_region *region = surface->mt->region;
+
+ /* TODO: handle other formats */
+ uint32_t format = surface->map_stencil_as_y_tiled
+ ? BRW_SURFACEFORMAT_R8_UNORM : BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+
+ uint32_t *surf = (uint32_t *)
+ brw_state_batch(brw, AUB_TRACE_SURFACE_STATE, 6 * 4, 32,
+ &wm_surf_offset);
+
+ surf[0] = (BRW_SURFACE_2D << BRW_SURFACE_TYPE_SHIFT |
+ BRW_SURFACE_MIPMAPLAYOUT_BELOW << BRW_SURFACE_MIPLAYOUT_SHIFT |
+ BRW_SURFACE_CUBEFACE_ENABLES |
+ format << BRW_SURFACE_FORMAT_SHIFT);
+
+ /* reloc */
+ surf[1] = region->bo->offset; /* No tile offsets needed */
+
+ surf[2] = (0 << BRW_SURFACE_LOD_SHIFT |
+ (width - 1) << BRW_SURFACE_WIDTH_SHIFT |
+ (height - 1) << BRW_SURFACE_HEIGHT_SHIFT);
+
+ uint32_t tiling = surface->map_stencil_as_y_tiled
+ ? BRW_SURFACE_TILED | BRW_SURFACE_TILED_Y
+ : brw_get_surface_tiling_bits(region->tiling);
+ uint32_t pitch_bytes = region->pitch * region->cpp;
+ if (surface->map_stencil_as_y_tiled)
+ pitch_bytes *= 2;
+ surf[3] = (tiling |
+ 0 << BRW_SURFACE_DEPTH_SHIFT |
+ (pitch_bytes - 1) << BRW_SURFACE_PITCH_SHIFT);
+
+ surf[4] = 0;
+
+ surf[5] = (0 << BRW_SURFACE_X_OFFSET_SHIFT |
+ 0 << BRW_SURFACE_Y_OFFSET_SHIFT |
+ (surface->mt->align_h == 4 ?
+ BRW_SURFACE_VERTICAL_ALIGN_ENABLE : 0));
+
+ /* Emit relocation to surface contents */
+ drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+ wm_surf_offset + 4,
+ region->bo,
+ surf[1] - region->bo->offset,
+ read_domains, write_domain);
+
+ return wm_surf_offset;
+}
+
+
+/* BINDING_TABLE. See brw_wm_binding_table(). */
+uint32_t
+gen6_blorp_emit_binding_table(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_surf_offset_renderbuffer,
+ uint32_t wm_surf_offset_texture)
+{
+ uint32_t wm_bind_bo_offset;
+ uint32_t *bind = (uint32_t *)
+ brw_state_batch(brw, AUB_TRACE_BINDING_TABLE,
+ sizeof(uint32_t) *
+ BRW_BLORP_NUM_BINDING_TABLE_ENTRIES,
+ 32, /* alignment */
+ &wm_bind_bo_offset);
+ bind[BRW_BLORP_RENDERBUFFER_BINDING_TABLE_INDEX] =
+ wm_surf_offset_renderbuffer;
+ bind[BRW_BLORP_TEXTURE_BINDING_TABLE_INDEX] = wm_surf_offset_texture;
+
+ return wm_bind_bo_offset;
+}
+
+
+/**
+ * SAMPLER_STATE. See brw_update_sampler_state().
+ */
+static uint32_t
+gen6_blorp_emit_sampler_state(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ uint32_t sampler_offset;
+
+ struct brw_sampler_state *sampler = (struct brw_sampler_state *)
+ brw_state_batch(brw, AUB_TRACE_SAMPLER_STATE,
+ sizeof(struct brw_sampler_state),
+ 32, &sampler_offset);
+ memset(sampler, 0, sizeof(*sampler));
+
+ sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
+ sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
+ sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
+
+ sampler->ss1.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss1.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss1.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+
+ sampler->ss0.min_mag_neq = 1;
+
+ /* Set LOD bias:
+ */
+ sampler->ss0.lod_bias = 0;
+
+ sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
+ sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
+
+ /* Set BaseMipLevel, MaxLOD, MinLOD:
+ *
+ * XXX: I don't think that using firstLevel, lastLevel works,
+ * because we always setup the surface state as if firstLevel ==
+ * level zero. Probably have to subtract firstLevel from each of
+ * these:
+ */
+ sampler->ss0.base_level = U_FIXED(0, 1);
+
+ sampler->ss1.max_lod = U_FIXED(0, 6);
+ sampler->ss1.min_lod = U_FIXED(0, 6);
+
+ sampler->ss3.non_normalized_coord = 1;
+
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MIN;
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MAG;
+
+ return sampler_offset;
+}
+
+
+/**
+ * 3DSTATE_SAMPLER_STATE_POINTERS. See upload_sampler_state_pointers().
+ */
+static void
+gen6_blorp_emit_sampler_state_pointers(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t sampler_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(4);
+ OUT_BATCH(_3DSTATE_SAMPLER_STATE_POINTERS << 16 |
+ VS_SAMPLER_STATE_CHANGE |
+ GS_SAMPLER_STATE_CHANGE |
+ PS_SAMPLER_STATE_CHANGE |
+ (4 - 2));
+ OUT_BATCH(0); /* VS */
+ OUT_BATCH(0); /* GS */
+ OUT_BATCH(sampler_offset);
ADVANCE_BATCH();
}
@@ -465,21 +702,27 @@ gen6_blorp_emit_sf_config(struct brw_context *brw,
/**
- * Disable thread dispatch (dw5.19) and enable the HiZ op.
+ * Enable or disable thread dispatch and set the HiZ op appropriately.
*/
static void
gen6_blorp_emit_wm_config(struct brw_context *brw,
- const brw_blorp_params *params)
+ const brw_blorp_params *params,
+ uint32_t prog_offset,
+ brw_blorp_prog_data *prog_data)
{
struct intel_context *intel = &brw->intel;
+ uint32_t dw2, dw4, dw5, dw6;
- /* Even though thread dispatch is disabled, max threads (dw5.25:31) must be
+ /* Even when thread dispatch is disabled, max threads (dw5.25:31) must be
* nonzero to prevent the GPU from hanging. See the valid ranges in the
* BSpec, Volume 2a.11 Windower, Section 3DSTATE_WM, Dword 5.25:31
* "Maximum Number Of Threads".
+ *
+ * To be safe (and to minimize extraneous code) we go ahead and fully
+ * configure the WM state whether or not there is a WM program.
*/
- uint32_t dw4 = 0;
+ dw2 = dw4 = dw5 = dw6 = 0;
switch (params->hiz_op) {
case GEN6_HIZ_OP_DEPTH_CLEAR:
assert(!"not implemented");
@@ -491,25 +734,89 @@ gen6_blorp_emit_wm_config(struct brw_context *brw,
case GEN6_HIZ_OP_HIZ_RESOLVE:
dw4 |= GEN6_WM_HIERARCHICAL_DEPTH_RESOLVE;
break;
+ case GEN6_HIZ_OP_NONE:
+ break;
default:
assert(0);
break;
}
+ dw4 |= GEN6_WM_STATISTICS_ENABLE;
+ dw5 |= GEN6_WM_LINE_AA_WIDTH_1_0;
+ dw5 |= GEN6_WM_LINE_END_CAP_AA_WIDTH_0_5;
+ dw5 |= (brw->max_wm_threads - 1) << GEN6_WM_MAX_THREADS_SHIFT;
+ dw6 |= 0 << GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; /* No interp */
+ dw6 |= 0 << GEN6_WM_NUM_SF_OUTPUTS_SHIFT; /* No inputs from SF */
+ if (params->use_wm_prog) {
+ dw2 |= 1 << GEN6_WM_SAMPLER_COUNT_SHIFT; /* Up to 4 samplers */
+ dw4 |= prog_data->first_curbe_grf << GEN6_WM_DISPATCH_START_GRF_SHIFT_0;
+ dw5 |= GEN6_WM_16_DISPATCH_ENABLE;
+ dw5 |= GEN6_WM_KILL_ENABLE; /* TODO: temporarily smash on */
+ dw5 |= GEN6_WM_DISPATCH_ENABLE; /* We are rendering */
+ }
BEGIN_BATCH(9);
OUT_BATCH(_3DSTATE_WM << 16 | (9 - 2));
- OUT_BATCH(0);
- OUT_BATCH(0);
- OUT_BATCH(0);
+ OUT_BATCH(params->use_wm_prog ? prog_offset : 0);
+ OUT_BATCH(dw2);
+ OUT_BATCH(0); /* No scratch needed */
OUT_BATCH(dw4);
- OUT_BATCH((brw->max_wm_threads - 1) << GEN6_WM_MAX_THREADS_SHIFT);
- OUT_BATCH((1 - 1) << GEN6_WM_NUM_SF_OUTPUTS_SHIFT); /* only position */
+ OUT_BATCH(dw5);
+ OUT_BATCH(dw6); /* only position */
+ OUT_BATCH(0); /* No other programs */
+ OUT_BATCH(0); /* No other programs */
+ ADVANCE_BATCH();
+}
+
+
+static void
+gen6_blorp_emit_constant_ps(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_push_const_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ /* Make sure the push constants fill an exact integer number of
+ * registers.
+ */
+ assert(sizeof(brw_blorp_wm_push_constants) % 32 == 0);
+
+ /* There must be at least one register worth of push constant data. */
+ assert(BRW_BLORP_NUM_PUSH_CONST_REGS > 0);
+
+ /* Enable push constant buffer 0. */
+ BEGIN_BATCH(5);
+ OUT_BATCH(_3DSTATE_CONSTANT_PS << 16 |
+ GEN6_CONSTANT_BUFFER_0_ENABLE |
+ (5 - 2));
+ OUT_BATCH(wm_push_const_offset + (BRW_BLORP_NUM_PUSH_CONST_REGS - 1));
+ OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(0);
ADVANCE_BATCH();
}
+/**
+ * 3DSTATE_BINDING_TABLE_POINTERS
+ */
+static void
+gen6_blorp_emit_binding_table_pointers(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_bind_bo_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(4);
+ OUT_BATCH(_3DSTATE_BINDING_TABLE_POINTERS << 16 |
+ GEN6_BINDING_TABLE_MODIFY_PS |
+ (4 - 2));
+ OUT_BATCH(0); /* vs -- ignored */
+ OUT_BATCH(0); /* gs -- ignored */
+ OUT_BATCH(wm_bind_bo_offset); /* wm/ps */
+ ADVANCE_BATCH();
+}
+
+
static void
gen6_blorp_emit_depth_stencil_config(struct brw_context *brw,
const brw_blorp_params *params)
@@ -606,6 +913,25 @@ gen6_blorp_emit_depth_stencil_config(struct brw_context *brw,
}
+static void
+gen6_blorp_emit_depth_disable(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(7);
+ OUT_BATCH(_3DSTATE_DEPTH_BUFFER << 16 | (7 - 2));
+ OUT_BATCH((BRW_DEPTHFORMAT_D32_FLOAT << 18) |
+ (BRW_SURFACE_NULL << 29));
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+}
+
+
/* 3DSTATE_CLEAR_PARAMS
*
* From the Sandybridge PRM, Volume 2, Part 1, Section 3DSTATE_CLEAR_PARAMS:
@@ -677,20 +1003,57 @@ gen6_blorp_exec(struct intel_context *intel,
{
struct gl_context *ctx = &intel->ctx;
struct brw_context *brw = brw_context(ctx);
+ brw_blorp_prog_data *prog_data = NULL;
+ uint32_t cc_blend_state_offset = 0;
+ uint32_t cc_state_offset = 0;
uint32_t depthstencil_offset;
+ uint32_t wm_push_const_offset = 0;
+ uint32_t wm_bind_bo_offset = 0;
+ uint32_t prog_offset = params->get_wm_prog(brw, &prog_data);
gen6_blorp_emit_batch_head(brw, params);
gen6_blorp_emit_vertices(brw, params);
gen6_blorp_emit_urb_config(brw, params);
+ if (params->use_wm_prog) {
+ cc_blend_state_offset = gen6_blorp_emit_blend_state(brw, params);
+ cc_state_offset = gen6_blorp_emit_cc_state(brw, params);
+ }
depthstencil_offset = gen6_blorp_emit_depth_stencil_state(brw, params);
- gen6_blorp_emit_cc_state_pointers(brw, params, depthstencil_offset);
+ gen6_blorp_emit_cc_state_pointers(brw, params, cc_blend_state_offset,
+ depthstencil_offset, cc_state_offset);
+ if (params->use_wm_prog) {
+ uint32_t wm_surf_offset_renderbuffer;
+ uint32_t wm_surf_offset_texture;
+ uint32_t sampler_offset;
+ wm_push_const_offset = gen6_blorp_emit_wm_constants(brw, params);
+ wm_surf_offset_renderbuffer =
+ gen6_blorp_emit_surface_state(brw, params, &params->dst,
+ I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER);
+ wm_surf_offset_texture =
+ gen6_blorp_emit_surface_state(brw, params, &params->src,
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ wm_bind_bo_offset =
+ gen6_blorp_emit_binding_table(brw, params,
+ wm_surf_offset_renderbuffer,
+ wm_surf_offset_texture);
+ sampler_offset = gen6_blorp_emit_sampler_state(brw, params);
+ gen6_blorp_emit_sampler_state_pointers(brw, params, sampler_offset);
+ }
gen6_blorp_emit_vs_disable(brw, params);
gen6_blorp_emit_gs_disable(brw, params);
gen6_blorp_emit_clip_disable(brw, params);
gen6_blorp_emit_sf_config(brw, params);
- gen6_blorp_emit_wm_config(brw, params);
-
- gen6_blorp_emit_depth_stencil_config(brw, params);
+ if (params->use_wm_prog)
+ gen6_blorp_emit_constant_ps(brw, params, wm_push_const_offset);
+ gen6_blorp_emit_wm_config(brw, params, prog_offset, prog_data);
+ if (params->use_wm_prog)
+ gen6_blorp_emit_binding_table_pointers(brw, params, wm_bind_bo_offset);
+
+ if (params->depth.mt)
+ gen6_blorp_emit_depth_stencil_config(brw, params);
+ else
+ gen6_blorp_emit_depth_disable(brw, params);
gen6_blorp_emit_clear_params(brw, params);
gen6_blorp_emit_drawing_rectangle(brw, params);
gen6_blorp_emit_primitive(brw, params);
diff --git a/src/mesa/drivers/dri/i965/gen7_blorp.cpp b/src/mesa/drivers/dri/i965/gen7_blorp.cpp
index 64badcc10d4..f10d0aab2f8 100644
--- a/src/mesa/drivers/dri/i965/gen7_blorp.cpp
+++ b/src/mesa/drivers/dri/i965/gen7_blorp.cpp
@@ -81,6 +81,36 @@ gen7_blorp_emit_urb_config(struct brw_context *brw,
}
+/* 3DSTATE_BLEND_STATE_POINTERS */
+static void
+gen7_blorp_emit_blend_state_pointer(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t cc_blend_state_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(_3DSTATE_BLEND_STATE_POINTERS << 16 | (2 - 2));
+ OUT_BATCH(cc_blend_state_offset | 1);
+ ADVANCE_BATCH();
+}
+
+
+/* 3DSTATE_CC_STATE_POINTERS */
+static void
+gen7_blorp_emit_cc_state_pointer(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t cc_state_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(_3DSTATE_CC_STATE_POINTERS << 16 | (2 - 2));
+ OUT_BATCH(cc_state_offset | 1);
+ ADVANCE_BATCH();
+}
+
+
/* 3DSTATE_DEPTH_STENCIL_STATE_POINTERS
*
* The offset is relative to CMD_STATE_BASE_ADDRESS.DynamicStateBaseAddress.
@@ -99,6 +129,134 @@ gen7_blorp_emit_depth_stencil_state_pointers(struct brw_context *brw,
}
+/* SURFACE_STATE for renderbuffer or texture surface (see
+ * brw_update_renderbuffer_surface and brw_update_texture_surface)
+ */
+static uint32_t
+gen7_blorp_emit_surface_state(struct brw_context *brw,
+ const brw_blorp_params *params,
+ const brw_blorp_surface_info *surface,
+ uint32_t read_domains, uint32_t write_domain)
+{
+ struct intel_context *intel = &brw->intel;
+
+ uint32_t wm_surf_offset;
+ uint32_t width, height;
+ surface->get_miplevel_dims(&width, &height);
+ if (surface->map_stencil_as_y_tiled) {
+ width *= 2;
+ height /= 2;
+ }
+ struct intel_region *region = surface->mt->region;
+
+ /* TODO: handle other formats */
+ uint32_t format = surface->map_stencil_as_y_tiled
+ ? BRW_SURFACEFORMAT_R8_UNORM : BRW_SURFACEFORMAT_B8G8R8A8_UNORM;
+
+ struct gen7_surface_state *surf = (struct gen7_surface_state *)
+ brw_state_batch(brw, AUB_TRACE_SURFACE_STATE, sizeof(*surf), 32,
+ &wm_surf_offset);
+ memset(surf, 0, sizeof(*surf));
+
+ if (surface->mt->align_h == 4)
+ surf->ss0.vertical_alignment = 1;
+ if (surface->mt->align_w == 8)
+ surf->ss0.horizontal_alignment = 1;
+
+ surf->ss0.surface_format = format;
+ surf->ss0.surface_type = BRW_SURFACE_2D;
+
+ /* reloc */
+ surf->ss1.base_addr = region->bo->offset; /* No tile offsets needed */
+
+ surf->ss2.width = width - 1;
+ surf->ss2.height = height - 1;
+
+ uint32_t tiling = surface->map_stencil_as_y_tiled
+ ? I915_TILING_Y : region->tiling;
+ gen7_set_surface_tiling(surf, tiling);
+
+ uint32_t pitch_bytes = region->pitch * region->cpp;
+ if (surface->map_stencil_as_y_tiled)
+ pitch_bytes *= 2;
+ surf->ss3.pitch = pitch_bytes - 1;
+
+ if (intel->is_haswell) {
+ surf->ss7.shader_chanel_select_r = HSW_SCS_RED;
+ surf->ss7.shader_chanel_select_g = HSW_SCS_GREEN;
+ surf->ss7.shader_chanel_select_b = HSW_SCS_BLUE;
+ surf->ss7.shader_chanel_select_a = HSW_SCS_ALPHA;
+ }
+
+ /* Emit relocation to surface contents */
+ drm_intel_bo_emit_reloc(brw->intel.batch.bo,
+ wm_surf_offset +
+ offsetof(struct gen7_surface_state, ss1),
+ region->bo,
+ surf->ss1.base_addr - region->bo->offset,
+ read_domains, write_domain);
+
+ return wm_surf_offset;
+}
+
+
+/**
+ * SAMPLER_STATE. See gen7_update_sampler_state().
+ */
+static uint32_t
+gen7_blorp_emit_sampler_state(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ uint32_t sampler_offset;
+
+ struct gen7_sampler_state *sampler = (struct gen7_sampler_state *)
+ brw_state_batch(brw, AUB_TRACE_SAMPLER_STATE,
+ sizeof(struct gen7_sampler_state),
+ 32, &sampler_offset);
+ memset(sampler, 0, sizeof(*sampler));
+
+ sampler->ss0.min_filter = BRW_MAPFILTER_LINEAR;
+ sampler->ss0.mip_filter = BRW_MIPFILTER_NONE;
+ sampler->ss0.mag_filter = BRW_MAPFILTER_LINEAR;
+
+ sampler->ss3.r_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss3.s_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+ sampler->ss3.t_wrap_mode = BRW_TEXCOORDMODE_CLAMP;
+
+ // sampler->ss0.min_mag_neq = 1;
+
+ /* Set LOD bias:
+ */
+ sampler->ss0.lod_bias = 0;
+
+ sampler->ss0.lod_preclamp = 1; /* OpenGL mode */
+ sampler->ss0.default_color_mode = 0; /* OpenGL/DX10 mode */
+
+ /* Set BaseMipLevel, MaxLOD, MinLOD:
+ *
+ * XXX: I don't think that using firstLevel, lastLevel works,
+ * because we always setup the surface state as if firstLevel ==
+ * level zero. Probably have to subtract firstLevel from each of
+ * these:
+ */
+ sampler->ss0.base_level = U_FIXED(0, 1);
+
+ sampler->ss1.max_lod = U_FIXED(0, 8);
+ sampler->ss1.min_lod = U_FIXED(0, 8);
+
+ sampler->ss3.non_normalized_coord = 1;
+
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MIN |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MIN;
+ sampler->ss3.address_round |= BRW_ADDRESS_ROUNDING_ENABLE_U_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_V_MAG |
+ BRW_ADDRESS_ROUNDING_ENABLE_R_MAG;
+
+ return sampler_offset;
+}
+
+
/* 3DSTATE_HS
*
* Disable the hull shader.
@@ -256,6 +414,14 @@ gen7_blorp_emit_wm_config(struct brw_context *brw,
assert(0);
break;
}
+ dw1 |= GEN7_WM_STATISTICS_ENABLE;
+ dw1 |= GEN7_WM_LINE_AA_WIDTH_1_0;
+ dw1 |= GEN7_WM_LINE_END_CAP_AA_WIDTH_0_5;
+ dw1 |= 0 << GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT; /* No interp */
+ if (params->use_wm_prog) {
+ dw1 |= GEN7_WM_KILL_ENABLE; /* TODO: temporarily smash on */
+ dw1 |= GEN7_WM_DISPATCH_ENABLE; /* We are rendering */
+ }
BEGIN_BATCH(3);
OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2));
@@ -278,17 +444,89 @@ gen7_blorp_emit_wm_config(struct brw_context *brw,
*/
static void
gen7_blorp_emit_ps_config(struct brw_context *brw,
- const brw_blorp_params *params)
+ const brw_blorp_params *params,
+ uint32_t prog_offset,
+ brw_blorp_prog_data *prog_data)
{
struct intel_context *intel = &brw->intel;
+ uint32_t dw2, dw4, dw5;
+ const int max_threads_shift = brw->intel.is_haswell ?
+ HSW_PS_MAX_THREADS_SHIFT : IVB_PS_MAX_THREADS_SHIFT;
+
+ dw2 = dw4 = dw5 = 0;
+ dw4 |= (brw->max_wm_threads - 1) << max_threads_shift;
+ dw4 |= GEN7_PS_32_DISPATCH_ENABLE;
+ if (intel->is_haswell)
+ dw4 |= SET_FIELD(1, HSW_PS_SAMPLE_MASK); /* 1 sample for now */
+ if (params->use_wm_prog) {
+ dw2 |= 1 << GEN7_PS_SAMPLER_COUNT_SHIFT; /* Up to 4 samplers */
+ dw4 |= GEN7_PS_PUSH_CONSTANT_ENABLE;
+ dw5 |= prog_data->first_curbe_grf << GEN7_PS_DISPATCH_START_GRF_SHIFT_0;
+ }
BEGIN_BATCH(8);
OUT_BATCH(_3DSTATE_PS << 16 | (8 - 2));
+ OUT_BATCH(params->use_wm_prog ? prog_offset : 0);
+ OUT_BATCH(dw2);
OUT_BATCH(0);
+ OUT_BATCH(dw4);
+ OUT_BATCH(dw5);
OUT_BATCH(0);
OUT_BATCH(0);
- OUT_BATCH(((brw->max_wm_threads - 1) << IVB_PS_MAX_THREADS_SHIFT) |
- GEN7_PS_32_DISPATCH_ENABLE);
+ ADVANCE_BATCH();
+}
+
+
+static void
+gen7_blorp_emit_binding_table_pointers_ps(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_bind_bo_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(_3DSTATE_BINDING_TABLE_POINTERS_PS << 16 | (2 - 2));
+ OUT_BATCH(wm_bind_bo_offset);
+ ADVANCE_BATCH();
+}
+
+
+static void
+gen7_blorp_emit_sampler_state_pointers_ps(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t sampler_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(2);
+ OUT_BATCH(_3DSTATE_SAMPLER_STATE_POINTERS_PS << 16 | (2 - 2));
+ OUT_BATCH(sampler_offset);
+ ADVANCE_BATCH();
+}
+
+
+static void
+gen7_blorp_emit_constant_ps(struct brw_context *brw,
+ const brw_blorp_params *params,
+ uint32_t wm_push_const_offset)
+{
+ struct intel_context *intel = &brw->intel;
+
+ /* Make sure the push constants fill an exact integer number of
+ * registers.
+ */
+ assert(sizeof(brw_blorp_wm_push_constants) % 32 == 0);
+
+ /* There must be at least one register worth of push constant data. */
+ assert(BRW_BLORP_NUM_PUSH_CONST_REGS > 0);
+
+ /* Enable push constant buffer 0. */
+ BEGIN_BATCH(7);
+ OUT_BATCH(_3DSTATE_CONSTANT_PS << 16 |
+ (7 - 2));
+ OUT_BATCH(BRW_BLORP_NUM_PUSH_CONST_REGS);
+ OUT_BATCH(0);
+ OUT_BATCH(wm_push_const_offset);
OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(0);
@@ -304,8 +542,10 @@ gen7_blorp_emit_depth_stencil_config(struct brw_context *brw,
uint32_t draw_x, draw_y;
uint32_t tile_mask_x, tile_mask_y;
- params->depth.get_draw_offsets(&draw_x, &draw_y);
- gen6_blorp_compute_tile_masks(params, &tile_mask_x, &tile_mask_y);
+ if (params->depth.mt) {
+ params->depth.get_draw_offsets(&draw_x, &draw_y);
+ gen6_blorp_compute_tile_masks(params, &tile_mask_x, &tile_mask_y);
+ }
/* 3DSTATE_DEPTH_BUFFER */
{
@@ -388,6 +628,24 @@ gen7_blorp_emit_depth_stencil_config(struct brw_context *brw,
}
+static void
+gen7_blorp_emit_depth_disable(struct brw_context *brw,
+ const brw_blorp_params *params)
+{
+ struct intel_context *intel = &brw->intel;
+
+ BEGIN_BATCH(7);
+ OUT_BATCH(GEN7_3DSTATE_DEPTH_BUFFER << 16 | (7 - 2));
+ OUT_BATCH(BRW_DEPTHFORMAT_D32_FLOAT << 18 | (BRW_SURFACE_NULL << 29));
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ OUT_BATCH(0);
+ ADVANCE_BATCH();
+}
+
+
/* 3DSTATE_CLEAR_PARAMS
*
* From the BSpec, Volume 2a.11 Windower, Section 1.5.6.3.2
@@ -439,14 +697,44 @@ gen7_blorp_exec(struct intel_context *intel,
{
struct gl_context *ctx = &intel->ctx;
struct brw_context *brw = brw_context(ctx);
+ brw_blorp_prog_data *prog_data = NULL;
+ uint32_t cc_blend_state_offset = 0;
+ uint32_t cc_state_offset = 0;
uint32_t depthstencil_offset;
+ uint32_t wm_push_const_offset = 0;
+ uint32_t wm_bind_bo_offset = 0;
+ uint32_t sampler_offset = 0;
+ uint32_t prog_offset = params->get_wm_prog(brw, &prog_data);
gen6_blorp_emit_batch_head(brw, params);
gen6_blorp_emit_vertices(brw, params);
gen7_blorp_emit_urb_config(brw, params);
+ if (params->use_wm_prog) {
+ cc_blend_state_offset = gen6_blorp_emit_blend_state(brw, params);
+ cc_state_offset = gen6_blorp_emit_cc_state(brw, params);
+ gen7_blorp_emit_blend_state_pointer(brw, params, cc_blend_state_offset);
+ gen7_blorp_emit_cc_state_pointer(brw, params, cc_state_offset);
+ }
depthstencil_offset = gen6_blorp_emit_depth_stencil_state(brw, params);
gen7_blorp_emit_depth_stencil_state_pointers(brw, params,
depthstencil_offset);
+ if (params->use_wm_prog) {
+ uint32_t wm_surf_offset_renderbuffer;
+ uint32_t wm_surf_offset_texture;
+ wm_push_const_offset = gen6_blorp_emit_wm_constants(brw, params);
+ wm_surf_offset_renderbuffer =
+ gen7_blorp_emit_surface_state(brw, params, &params->dst,
+ I915_GEM_DOMAIN_RENDER,
+ I915_GEM_DOMAIN_RENDER);
+ wm_surf_offset_texture =
+ gen7_blorp_emit_surface_state(brw, params, &params->src,
+ I915_GEM_DOMAIN_SAMPLER, 0);
+ wm_bind_bo_offset =
+ gen6_blorp_emit_binding_table(brw, params,
+ wm_surf_offset_renderbuffer,
+ wm_surf_offset_texture);
+ sampler_offset = gen7_blorp_emit_sampler_state(brw, params);
+ }
gen6_blorp_emit_vs_disable(brw, params);
gen7_blorp_emit_hs_disable(brw, params);
gen7_blorp_emit_te_disable(brw, params);
@@ -456,9 +744,18 @@ gen7_blorp_exec(struct intel_context *intel,
gen6_blorp_emit_clip_disable(brw, params);
gen7_blorp_emit_sf_config(brw, params);
gen7_blorp_emit_wm_config(brw, params);
- gen7_blorp_emit_ps_config(brw, params);
+ if (params->use_wm_prog) {
+ gen7_blorp_emit_binding_table_pointers_ps(brw, params,
+ wm_bind_bo_offset);
+ gen7_blorp_emit_sampler_state_pointers_ps(brw, params, sampler_offset);
+ gen7_blorp_emit_constant_ps(brw, params, wm_push_const_offset);
+ }
+ gen7_blorp_emit_ps_config(brw, params, prog_offset, prog_data);
- gen7_blorp_emit_depth_stencil_config(brw, params);
+ if (params->depth.mt)
+ gen7_blorp_emit_depth_stencil_config(brw, params);
+ else
+ gen7_blorp_emit_depth_disable(brw, params);
gen7_blorp_emit_clear_params(brw, params);
gen6_blorp_emit_drawing_rectangle(brw, params);
gen7_blorp_emit_primitive(brw, params);
diff --git a/src/mesa/drivers/dri/intel/intel_fbo.c b/src/mesa/drivers/dri/intel/intel_fbo.c
index 2f95ad06025..f92d78f378a 100644
--- a/src/mesa/drivers/dri/intel/intel_fbo.c
+++ b/src/mesa/drivers/dri/intel/intel_fbo.c
@@ -823,6 +823,15 @@ intel_blit_framebuffer(struct gl_context *ctx,
if (mask == 0x0)
return;
+#ifndef I915
+ mask = brw_blorp_framebuffer(intel_context(ctx),
+ srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ mask, filter);
+ if (mask == 0x0)
+ return;
+#endif
+
_mesa_meta_BlitFramebuffer(ctx,
srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1,