* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file iris_program.c
+ *
+ * This file contains the driver interface for compiling shaders.
+ *
+ * See iris_program_cache.c for the in-memory program cache where the
+ * compiled shaders are stored.
+ */
+
#include <stdio.h>
#include <errno.h>
#include "pipe/p_defines.h"
return p_atomic_inc_return(&screen->program_id);
}
+/**
+ * An uncompiled, API-facing shader. This is the Gallium CSO for shaders.
+ * It primarily contains the NIR for the shader.
+ *
+ * Each API-facing shader can be compiled into multiple shader variants,
+ * based on non-orthogonal state dependencies, recorded in the shader key.
+ *
+ * See iris_compiled_shader, which represents a compiled shader variant.
+ */
struct iris_uncompiled_shader {
nir_shader *nir;
// XXX: need unify_interfaces() at link time...
+/**
+ * The pipe->create_[stage]_state() driver hooks.
+ *
+ * Performs basic NIR preprocessing, records any state dependencies, and
+ * returns an iris_uncompiled_shader as the Gallium CSO.
+ *
+ * Actual shader compilation to assembly happens later, at first use.
+ */
static void *
iris_create_shader_state(struct pipe_context *ctx,
const struct pipe_shader_state *state)
break;
}
+ // XXX: precompile!
+
return ish;
}
+/**
+ * The pipe->delete_[stage]_state() driver hooks.
+ *
+ * Frees the iris_uncompiled_shader.
+ */
static void
iris_delete_shader_state(struct pipe_context *ctx, void *state)
{
free(ish);
}
+/**
+ * The pipe->bind_[stage]_state() driver hook.
+ *
+ * Binds an uncompiled shader as the current one for a particular stage.
+ * Updates dirty tracking to account for the shader's NOS.
+ */
static void
bind_state(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
ice->shaders.uncompiled[stage] = ish;
ice->state.dirty |= dirty_bit;
+ /* Record that CSOs need to mark IRIS_DIRTY_UNCOMPILED_XS when they change
+ * (or that they no longer need to do so).
+ */
for (int i = 0; i < IRIS_NOS_COUNT; i++) {
if (nos & (1 << i))
ice->state.dirty_for_nos[i] |= dirty_bit;
{
struct iris_context *ice = (struct iris_context *)ctx;
+ /* Enabling/disabling optional stages requires a URB reconfiguration. */
if (!!state != !!ice->shaders.uncompiled[MESA_SHADER_TESS_EVAL])
ice->state.dirty |= IRIS_DIRTY_URB;
{
struct iris_context *ice = (struct iris_context *)ctx;
+ /* Enabling/disabling optional stages requires a URB reconfiguration. */
if (!!state != !!ice->shaders.uncompiled[MESA_SHADER_GEOMETRY])
ice->state.dirty |= IRIS_DIRTY_URB;
return next_binding_table_offset;
}
+/**
+ * Associate NIR uniform variables with the prog_data->param[] mechanism
+ * used by the backend. Also, decide which UBOs we'd like to push in an
+ * ideal situation (though the backend can reduce this).
+ */
static void
iris_setup_uniforms(const struct brw_compiler *compiler,
void *mem_ctx,
brw_nir_analyze_ubo_ranges(compiler, nir, NULL, prog_data->ubo_ranges);
}
+/**
+ * If we still have regular uniforms as push constants after the backend
+ * compilation, set up a UBO range for them. This will be used to fill
+ * out the 3DSTATE_CONSTANT_* packets which cause the data to be pushed.
+ */
static void
iris_setup_push_uniform_range(const struct brw_compiler *compiler,
struct brw_stage_prog_data *prog_data)
}
}
+/**
+ * Compile a vertex shader, and upload the assembly.
+ */
static bool
iris_compile_vs(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
return true;
}
+/**
+ * Update the current vertex shader variant.
+ *
+ * Fill out the key, look in the cache, compile and bind if needed.
+ */
static void
iris_update_compiled_vs(struct iris_context *ice)
{
UNUSED bool success = iris_compile_vs(ice, ish, &key);
}
+/**
+ * Get the shader_info for a given stage, or NULL if the stage is disabled.
+ */
const struct shader_info *
iris_get_shader_info(const struct iris_context *ice, gl_shader_stage stage)
{
}
}
+/**
+ * Compile a tessellation control shader, and upload the assembly.
+ */
static bool
iris_compile_tcs(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
return true;
}
+/**
+ * Update the current tessellation control shader variant.
+ *
+ * Fill out the key, look in the cache, compile and bind if needed.
+ */
static void
iris_update_compiled_tcs(struct iris_context *ice)
{
UNUSED bool success = iris_compile_tcs(ice, tcs, &key);
}
+/**
+ * Compile a tessellation evaluation shader, and upload the assembly.
+ */
static bool
iris_compile_tes(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
return true;
}
+/**
+ * Update the current tessellation evaluation shader variant.
+ *
+ * Fill out the key, look in the cache, compile and bind if needed.
+ */
static void
iris_update_compiled_tes(struct iris_context *ice)
{
UNUSED bool success = iris_compile_tes(ice, ish, &key);
}
+/**
+ * Compile a geometry shader, and upload the assembly.
+ */
static bool
iris_compile_gs(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
return true;
}
-
+/**
+ * Update the current geometry shader variant.
+ *
+ * Fill out the key, look in the cache, compile and bind if needed.
+ */
static void
iris_update_compiled_gs(struct iris_context *ice)
{
UNUSED bool success = iris_compile_gs(ice, ish, &key);
}
+/**
+ * Compile a fragment (pixel) shader, and upload the assembly.
+ */
static bool
iris_compile_fs(struct iris_context *ice,
struct iris_uncompiled_shader *ish,
return true;
}
+/**
+ * Update the current fragment shader variant.
+ *
+ * Fill out the key, look in the cache, compile and bind if needed.
+ */
static void
iris_update_compiled_fs(struct iris_context *ice)
{
iris_compile_fs(ice, ish, &key, ice->shaders.last_vue_map);
}
+/**
+ * Get the compiled shader for the last enabled geometry stage.
+ *
+ * This stage is the one which will feed stream output and the rasterizer.
+ */
static struct iris_compiled_shader *
last_vue_shader(struct iris_context *ice)
{
return ice->shaders.prog[MESA_SHADER_VERTEX];
}
+/**
+ * Update the last enabled stage's VUE map.
+ *
+ * When the shader feeding the rasterizer's output interface changes, we
+ * need to re-emit various packets.
+ */
static void
update_last_vue_map(struct iris_context *ice,
struct brw_stage_prog_data *prog_data)
ice->shaders.last_vue_map = &vue_prog_data->vue_map;
}
+/**
+ * Get the prog_data for a given stage, or NULL if the stage is disabled.
+ */
static struct brw_vue_prog_data *
get_vue_prog_data(struct iris_context *ice, gl_shader_stage stage)
{
return (void *) ice->shaders.prog[stage]->prog_data;
}
+/**
+ * Update the current shader variants for the given state.
+ *
+ * This should be called on every draw call to ensure that the correct
+ * shaders are bound. It will also flag any dirty state triggered by
+ * swapping out those shaders.
+ */
void
iris_update_compiled_shaders(struct iris_context *ice)
{
iris_update_compiled_fs(ice);
// ...
+ /* Changing shader interfaces may require a URB configuration. */
if (!(dirty & IRIS_DIRTY_URB)) {
for (int i = MESA_SHADER_VERTEX; i <= MESA_SHADER_GEOMETRY; i++) {
struct brw_vue_prog_data *old = old_prog_datas[i];
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+
+/**
+ * @file iris_state.c
+ *
+ * ============================= GENXML CODE =============================
+ * [This file is compiled once per generation.]
+ * =======================================================================
+ *
+ * This is the main state upload code.
+ *
+ * Gallium uses Constant State Objects, or CSOs, for most state. Large,
+ * complex, or highly reusable state can be created once, and bound and
+ * rebound multiple times. This is modeled with the pipe->create_*_state()
+ * and pipe->bind_*_state() hooks. Highly dynamic or inexpensive state is
+ * streamed out on the fly, via pipe->set_*_state() hooks.
+ *
+ * OpenGL involves frequently mutating context state, which is mirrored in
+ * core Mesa by highly mutable data structures. However, most applications
+ * typically draw the same things over and over - from frame to frame, most
+ * of the same objects are still visible and need to be redrawn. So, rather
+ * than inventing new state all the time, applications usually mutate to swap
+ * between known states that we've seen before.
+ *
+ * Gallium isolates us from this mutation by tracking API state, and
+ * distilling it into a set of Constant State Objects, or CSOs. Large,
+ * complex, or typically reusable state can be created once, then reused
+ * multiple times. Drivers can create and store their own associated data.
+ * This create/bind model corresponds to the pipe->create_*_state() and
+ * pipe->bind_*_state() driver hooks.
+ *
+ * Some state is cheap to create, or expected to be highly dynamic. Rather
+ * than creating and caching piles of CSOs for these, Gallium simply streams
+ * them out, via the pipe->set_*_state() driver hooks.
+ *
+ * To reduce draw time overhead, we try to compute as much state at create
+ * time as possible. Wherever possible, we translate the Gallium pipe state
+ * to 3DSTATE commands, and store those commands in the CSO. At draw time,
+ * we can simply memcpy them into a batch buffer.
+ *
+ * No hardware matches the abstraction perfectly, so some commands require
+ * information from multiple CSOs. In this case, we can store two copies
+ * of the packet (one in each CSO), and simply | together their DWords at
+ * draw time. Sometimes the second set is trivial (one or two fields), so
+ * we simply pack it at draw time.
+ *
+ * There are two main components in the file below. First, the CSO hooks
+ * create/bind/track state. The second are the draw-time upload functions,
+ * iris_upload_render_state() and iris_upload_compute_state(), which read
+ * the context state and emit the commands into the actual batch.
+ */
+
#include <stdio.h>
#include <errno.h>
#define MOCS_WB (2 << 1)
+/**
+ * Statically assert that PIPE_* enums match the hardware packets.
+ * (As long as they match, we don't need to translate them.)
+ */
UNUSED static void pipe_asserts()
{
#define PIPE_ASSERT(x) STATIC_ASSERT((int)x)
return map[pipe_polymode];
}
+static unsigned
+translate_mip_filter(enum pipe_tex_mipfilter pipe_mip)
+{
+ static const unsigned map[] = {
+ [PIPE_TEX_MIPFILTER_NEAREST] = MIPFILTER_NEAREST,
+ [PIPE_TEX_MIPFILTER_LINEAR] = MIPFILTER_LINEAR,
+ [PIPE_TEX_MIPFILTER_NONE] = MIPFILTER_NONE,
+ };
+ return map[pipe_mip];
+}
+
+static uint32_t
+translate_wrap(unsigned pipe_wrap)
+{
+ static const unsigned map[] = {
+ [PIPE_TEX_WRAP_REPEAT] = TCM_WRAP,
+ [PIPE_TEX_WRAP_CLAMP] = TCM_HALF_BORDER,
+ [PIPE_TEX_WRAP_CLAMP_TO_EDGE] = TCM_CLAMP,
+ [PIPE_TEX_WRAP_CLAMP_TO_BORDER] = TCM_CLAMP_BORDER,
+ [PIPE_TEX_WRAP_MIRROR_REPEAT] = TCM_MIRROR,
+ [PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE] = TCM_MIRROR_ONCE,
+
+ /* These are unsupported. */
+ [PIPE_TEX_WRAP_MIRROR_CLAMP] = -1,
+ [PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER] = -1,
+ };
+ return map[pipe_wrap];
+}
+
static struct iris_address
ro_bo(struct iris_bo *bo, uint64_t offset)
{
- /* Not for CSOs! */
+ /* CSOs must pass NULL for bo! Otherwise it will add the BO to the
+ * validation list at CSO creation time, instead of draw time.
+ */
return (struct iris_address) { .bo = bo, .offset = offset };
}
static struct iris_address
rw_bo(struct iris_bo *bo, uint64_t offset)
{
- /* Not for CSOs! */
+ /* CSOs must pass NULL for bo! Otherwise it will add the BO to the
+ * validation list at CSO creation time, instead of draw time.
+ */
return (struct iris_address) { .bo = bo, .offset = offset, .write = true };
}
+/**
+ * Allocate space for some indirect state.
+ *
+ * Return a pointer to the map (to fill it out) and a state ref (for
+ * referring to the state in GPU commands).
+ */
static void *
upload_state(struct u_upload_mgr *uploader,
struct iris_state_ref *ref,
return p;
}
+/**
+ * Stream out temporary/short-lived state.
+ *
+ * This allocates space, pins the BO, and includes the BO address in the
+ * returned offset (which works because all state lives in 32-bit memory
+ * zones).
+ */
static uint32_t *
stream_state(struct iris_batch *batch,
struct u_upload_mgr *uploader,
return ptr;
}
+/**
+ * stream_state() + memcpy.
+ */
static uint32_t
emit_state(struct iris_batch *batch,
struct u_upload_mgr *uploader,
return offset;
}
+/**
+ * Did field 'x' change between 'old_cso' and 'new_cso'?
+ *
+ * (If so, we may want to set some dirty flags.)
+ */
#define cso_changed(x) (!old_cso || (old_cso->x != new_cso->x))
#define cso_changed_memcmp(x) \
(!old_cso || memcmp(old_cso->x, new_cso->x, sizeof(old_cso->x)) != 0)
+/**
+ * Upload the initial GPU state for a render context.
+ *
+ * This sets some invariant state that needs to be programmed a particular
+ * way, but we never actually change.
+ */
static void
iris_init_render_context(struct iris_screen *screen,
struct iris_batch *batch,
/* XXX: PIPE_CONTROLs */
+ /* We program STATE_BASE_ADDRESS once at context initialization time.
+ * Each base address points at a 4GB memory zone, and never needs to
+ * change. See iris_bufmgr.h for a description of the memory zones.
+ */
iris_emit_cmd(batch, GENX(STATE_BASE_ADDRESS), sba) {
#if 0
// XXX: MOCS is stupid for this.
sba.DynamicStateBufferSize = 0xfffff;
}
+ /* 3DSTATE_DRAWING_RECTANGLE is non-pipelined, so we want to avoid
+ * changing it dynamically. We set it to the maximum size here, and
+ * instead include the render target dimensions in the viewport, so
+ * viewport extents clipping takes care of pruning stray geometry.
+ */
iris_emit_cmd(batch, GENX(3DSTATE_DRAWING_RECTANGLE), rect) {
rect.ClippedDrawingRectangleXMax = UINT16_MAX;
rect.ClippedDrawingRectangleYMax = UINT16_MAX;
}
+
+ /* Set the initial MSAA sample positions. */
iris_emit_cmd(batch, GENX(3DSTATE_SAMPLE_PATTERN), pat) {
GEN_SAMPLE_POS_1X(pat._1xSample);
GEN_SAMPLE_POS_2X(pat._2xSample);
GEN_SAMPLE_POS_8X(pat._8xSample);
GEN_SAMPLE_POS_16X(pat._16xSample);
}
+
+ /* Use the legacy AA line coverage computation. */
iris_emit_cmd(batch, GENX(3DSTATE_AA_LINE_PARAMETERS), foo);
+
+ /* Disable chromakeying (it's for media) */
iris_emit_cmd(batch, GENX(3DSTATE_WM_CHROMAKEY), foo);
+
+ /* We want regular rendering, not special HiZ operations. */
iris_emit_cmd(batch, GENX(3DSTATE_WM_HZ_OP), foo);
- /* XXX: may need to set an offset for origin-UL framebuffers */
+
+ /* No polygon stippling offsets are necessary. */
+ // XXX: may need to set an offset for origin-UL framebuffers
iris_emit_cmd(batch, GENX(3DSTATE_POLY_STIPPLE_OFFSET), foo);
- /* Just assign a static partitioning. */
+ /* Set a static partitioning of the push constant area. */
+ // XXX: this may be a bad idea...could starve the push ringbuffers...
for (int i = 0; i <= MESA_SHADER_FRAGMENT; i++) {
iris_emit_cmd(batch, GENX(3DSTATE_PUSH_CONSTANT_ALLOC_VS), alloc) {
alloc._3DCommandSubOpcode = 18 + i;
}
struct iris_vertex_buffer_state {
+ /** The 3DSTATE_VERTEX_BUFFERS hardware packet. */
uint32_t vertex_buffers[1 + 33 * GENX(VERTEX_BUFFER_STATE_length)];
+
+ /** The resource to source vertex data from. */
struct pipe_resource *resources[33];
+
+ /** The number of bound vertex buffers. */
unsigned num_buffers;
};
struct iris_depth_buffer_state {
+ /* Depth/HiZ/Stencil related hardware packets. */
uint32_t packets[GENX(3DSTATE_DEPTH_BUFFER_length) +
GENX(3DSTATE_STENCIL_BUFFER_length) +
GENX(3DSTATE_HIER_DEPTH_BUFFER_length) +
};
/**
- * State that can't be stored directly in iris_context because the data
- * layout varies per generation.
+ * Generation-specific context state (ice->state.genx->...).
+ *
+ * Most state can go in iris_context directly, but these encode hardware
+ * packets which vary by generation.
*/
struct iris_genx_state {
/** SF_CLIP_VIEWPORT */
uint32_t streamout[4 * GENX(3DSTATE_STREAMOUT_length)];
};
+// XXX: move this to iris_draw.c
static void
iris_launch_grid(struct pipe_context *ctx, const struct pipe_grid_info *info)
{
}
+/**
+ * The pipe->set_blend_color() driver hook.
+ *
+ * This corresponds to our COLOR_CALC_STATE.
+ */
static void
iris_set_blend_color(struct pipe_context *ctx,
const struct pipe_blend_color *state)
{
struct iris_context *ice = (struct iris_context *) ctx;
+ /* Our COLOR_CALC_STATE is exactly pipe_blend_color, so just memcpy */
memcpy(&ice->state.blend_color, state, sizeof(struct pipe_blend_color));
ice->state.dirty |= IRIS_DIRTY_COLOR_CALC_STATE;
}
+/**
+ * Gallium CSO for blend state (see pipe_blend_state).
+ */
struct iris_blend_state {
/** Partial 3DSTATE_PS_BLEND */
uint32_t ps_blend[GENX(3DSTATE_PS_BLEND_length)];
bool alpha_to_coverage; /* for shader key */
};
+/**
+ * The pipe->create_blend_state() driver hook.
+ *
+ * Translates a pipe_blend_state into iris_blend_state.
+ */
static void *
iris_create_blend_state(struct pipe_context *ctx,
const struct pipe_blend_state *state)
return cso;
}
+/**
+ * The pipe->bind_blend_state() driver hook.
+ *
+ * Bind a blending CSO and flag related dirty bits.
+ */
static void
iris_bind_blend_state(struct pipe_context *ctx, void *state)
{
ice->state.dirty |= ice->state.dirty_for_nos[IRIS_NOS_BLEND];
}
+/**
+ * Gallium CSO for depth, stencil, and alpha testing state.
+ */
struct iris_depth_stencil_alpha_state {
- /** Partial 3DSTATE_WM_DEPTH_STENCIL */
+ /** Partial 3DSTATE_WM_DEPTH_STENCIL. */
uint32_t wmds[GENX(3DSTATE_WM_DEPTH_STENCIL_length)];
- /** Outbound to BLEND_STATE, 3DSTATE_PS_BLEND, COLOR_CALC_STATE */
+ /** Outbound to BLEND_STATE, 3DSTATE_PS_BLEND, COLOR_CALC_STATE. */
struct pipe_alpha_state alpha;
};
+/**
+ * The pipe->create_depth_stencil_alpha_state() driver hook.
+ *
+ * We encode most of 3DSTATE_WM_DEPTH_STENCIL, and just save off the alpha
+ * testing state since we need pieces of it in a variety of places.
+ */
static void *
iris_create_zsa_state(struct pipe_context *ctx,
const struct pipe_depth_stencil_alpha_state *state)
return cso;
}
+/**
+ * The pipe->bind_depth_stencil_alpha_state() driver hook.
+ *
+ * Bind a depth/stencil/alpha CSO and flag related dirty bits.
+ */
static void
iris_bind_zsa_state(struct pipe_context *ctx, void *state)
{
ice->state.dirty |= ice->state.dirty_for_nos[IRIS_NOS_DEPTH_STENCIL_ALPHA];
}
+/**
+ * Gallium CSO for rasterizer state.
+ */
struct iris_rasterizer_state {
uint32_t sf[GENX(3DSTATE_SF_length)];
uint32_t clip[GENX(3DSTATE_CLIP_length)];
uint16_t sprite_coord_enable;
};
+/**
+ * The pipe->create_rasterizer_state() driver hook.
+ */
static void *
iris_create_rasterizer_state(struct pipe_context *ctx,
const struct pipe_rasterizer_state *state)
}
#endif
+ // XXX: it may make more sense just to store the pipe_rasterizer_state,
+ // we're copying a lot of booleans here. But we don't need all of them...
+
cso->multisample = state->multisample;
cso->force_persample_interp = state->force_persample_interp;
cso->clip_halfz = state->clip_halfz;
return cso;
}
+/**
+ * The pipe->bind_rasterizer_state() driver hook.
+ *
+ * Bind a rasterizer CSO and flag related dirty bits.
+ */
static void
iris_bind_rasterizer_state(struct pipe_context *ctx, void *state)
{
ice->state.dirty |= ice->state.dirty_for_nos[IRIS_NOS_RASTERIZER];
}
-static uint32_t
-translate_wrap(unsigned pipe_wrap)
-{
- static const unsigned map[] = {
- [PIPE_TEX_WRAP_REPEAT] = TCM_WRAP,
- [PIPE_TEX_WRAP_CLAMP] = TCM_HALF_BORDER,
- [PIPE_TEX_WRAP_CLAMP_TO_EDGE] = TCM_CLAMP,
- [PIPE_TEX_WRAP_CLAMP_TO_BORDER] = TCM_CLAMP_BORDER,
- [PIPE_TEX_WRAP_MIRROR_REPEAT] = TCM_MIRROR,
- [PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE] = TCM_MIRROR_ONCE,
-
- /* These are unsupported. */
- [PIPE_TEX_WRAP_MIRROR_CLAMP] = -1,
- [PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER] = -1,
- };
- return map[pipe_wrap];
-}
-
/**
* Return true if the given wrap mode requires the border color to exist.
+ *
+ * (We can skip uploading it if the sampler isn't going to use it.)
*/
static bool
wrap_mode_needs_border_color(unsigned wrap_mode)
return wrap_mode == TCM_CLAMP_BORDER || wrap_mode == TCM_HALF_BORDER;
}
-static unsigned
-translate_mip_filter(enum pipe_tex_mipfilter pipe_mip)
-{
- static const unsigned map[] = {
- [PIPE_TEX_MIPFILTER_NEAREST] = MIPFILTER_NEAREST,
- [PIPE_TEX_MIPFILTER_LINEAR] = MIPFILTER_LINEAR,
- [PIPE_TEX_MIPFILTER_NONE] = MIPFILTER_NONE,
- };
- return map[pipe_mip];
-}
-
+/**
+ * Gallium CSO for sampler state.
+ */
struct iris_sampler_state {
+ // XXX: do we need this
struct pipe_sampler_state base;
bool needs_border_color;
uint32_t sampler_state[GENX(SAMPLER_STATE_length)];
};
+/**
+ * The pipe->create_sampler_state() driver hook.
+ *
+ * We fill out SAMPLER_STATE (except for the border color pointer), and
+ * store that on the CPU. It doesn't make sense to upload it to a GPU
+ * buffer object yet, because 3DSTATE_SAMPLER_STATE_POINTERS requires
+ * all bound sampler states to be in contiguous memor.
+ */
static void *
iris_create_sampler_state(struct pipe_context *ctx,
const struct pipe_sampler_state *state)
return cso;
}
+/**
+ * The pipe->bind_sampler_states() driver hook.
+ *
+ * Now that we know all the sampler states, we upload them all into a
+ * contiguous area of GPU memory, for 3DSTATE_SAMPLER_STATE_POINTERS_*.
+ * We also fill out the border color state pointers at this point.
+ *
+ * We could defer this work to draw time, but we assume that binding
+ * will be less frequent than drawing.
+ */
+// XXX: this may be a bad idea, need to make sure that st/mesa calls us
+// XXX: with the complete set of shaders. If it makes multiple calls to
+// XXX: things one at a time, we could waste a lot of time assembling things.
+// XXX: it doesn't even BUY us anything to do it here, because we only flag
+// XXX: IRIS_DIRTY_SAMPLER_STATE when this is called...
static void
iris_bind_sampler_states(struct pipe_context *ctx,
enum pipe_shader_type p_stage,
ice->state.dirty |= IRIS_DIRTY_SAMPLER_STATES_VS << stage;
}
+/**
+ * Gallium CSO for sampler views (texture views).
+ *
+ * In addition to the normal pipe_resource, this adds an ISL view
+ * which may reinterpret the format or restrict levels/layers.
+ *
+ * These can also be linear texture buffers.
+ */
struct iris_sampler_view {
+ // XXX: just store the resource, not the rest of this
struct pipe_sampler_view pipe;
struct isl_view view;
};
/**
- * Convert an swizzle enumeration (i.e. PIPE_SWIZZLE_X) to one of the Gen7.5+
- * "Shader Channel Select" enumerations (i.e. HSW_SCS_RED). The mappings are
+ * Convert an swizzle enumeration (i.e. PIPE_SWIZZLE_X) to one of the HW's
+ * "Shader Channel Select" enumerations (i.e. SCS_RED). The mappings are
*
* SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_W, SWIZZLE_ZERO, SWIZZLE_ONE
* 0 1 2 3 4 5
* SCS_RED, SCS_GREEN, SCS_BLUE, SCS_ALPHA, SCS_ZERO, SCS_ONE
*
* which is simply adding 4 then modding by 8 (or anding with 7).
- *
- * We then may need to apply workarounds for textureGather hardware bugs.
*/
static enum isl_channel_select
pipe_swizzle_to_isl_channel(enum pipe_swizzle swizzle)
return (swizzle + 4) & 7;
}
+/**
+ * The pipe->create_sampler_view() driver hook.
+ */
static struct pipe_sampler_view *
iris_create_sampler_view(struct pipe_context *ctx,
struct pipe_resource *tex,
(itex->surf.usage & ISL_SURF_USAGE_CUBE_BIT),
};
+ /* Fill out SURFACE_STATE for this view. */
if (tmpl->target != PIPE_BUFFER) {
isv->view.base_level = tmpl->u.tex.first_level;
isv->view.levels = tmpl->u.tex.last_level - tmpl->u.tex.first_level + 1;
return &isv->pipe;
}
+static void
+iris_sampler_view_destroy(struct pipe_context *ctx,
+ struct pipe_sampler_view *state)
+{
+ struct iris_sampler_view *isv = (void *) state;
+ pipe_resource_reference(&state->texture, NULL);
+ pipe_resource_reference(&isv->surface_state.res, NULL);
+ free(isv);
+}
+
+/**
+ * The pipe->create_surface() driver hook.
+ *
+ * In Gallium nomenclature, "surfaces" are a view of a resource that
+ * can be bound as a render target or depth/stencil buffer.
+ */
static struct pipe_surface *
iris_create_surface(struct pipe_context *ctx,
struct pipe_resource *tex,
.usage = usage,
};
- /* Bail early for depth/stencil */
+ /* Bail early for depth/stencil - we don't want SURFACE_STATE for them. */
if (res->surf.usage & (ISL_SURF_USAGE_DEPTH_BIT |
ISL_SURF_USAGE_STENCIL_BIT))
return psurf;
return psurf;
}
+/**
+ * The pipe->set_sampler_views() driver hook.
+ */
static void
iris_set_sampler_views(struct pipe_context *ctx,
enum pipe_shader_type p_stage,
ice->state.dirty |= (IRIS_DIRTY_BINDINGS_VS << stage);
}
+static void
+iris_surface_destroy(struct pipe_context *ctx, struct pipe_surface *p_surf)
+{
+ struct iris_surface *surf = (void *) p_surf;
+ pipe_resource_reference(&p_surf->texture, NULL);
+ pipe_resource_reference(&surf->surface_state.res, NULL);
+ free(surf);
+}
+
+// XXX: actually implement user clip planes
static void
iris_set_clip_state(struct pipe_context *ctx,
const struct pipe_clip_state *state)
{
}
+/**
+ * The pipe->set_polygon_stipple() driver hook.
+ */
static void
iris_set_polygon_stipple(struct pipe_context *ctx,
const struct pipe_poly_stipple *state)
ice->state.dirty |= IRIS_DIRTY_POLYGON_STIPPLE;
}
+/**
+ * The pipe->set_sample_mask() driver hook.
+ */
static void
iris_set_sample_mask(struct pipe_context *ctx, unsigned sample_mask)
{
struct iris_context *ice = (struct iris_context *) ctx;
+ /* We only support 16x MSAA, so we have 16 bits of sample maks.
+ * st/mesa may pass us 0xffffffff though, meaning "enable all samples".
+ */
ice->state.sample_mask = sample_mask & 0xffff;
ice->state.dirty |= IRIS_DIRTY_SAMPLE_MASK;
}
+/**
+ * The pipe->set_scissor_states() driver hook.
+ *
+ * This corresponds to our SCISSOR_RECT state structures. It's an
+ * exact match, so we just store them, and memcpy them out later.
+ */
static void
iris_set_scissor_states(struct pipe_context *ctx,
unsigned start_slot,
ice->state.dirty |= IRIS_DIRTY_SCISSOR_RECT;
}
+/**
+ * The pipe->set_stencil_ref() driver hook.
+ *
+ * This is added to 3DSTATE_WM_DEPTH_STENCIL dynamically at draw time.
+ */
static void
iris_set_stencil_ref(struct pipe_context *ctx,
const struct pipe_stencil_ref *state)
}
#endif
+/**
+ * The pipe->set_viewport_states() driver hook.
+ *
+ * This corresponds to our SF_CLIP_VIEWPORT states. We can't calculate
+ * the guardband yet, as we need the framebuffer dimensions, but we can
+ * at least fill out the rest.
+ */
static void
iris_set_viewport_states(struct pipe_context *ctx,
unsigned start_slot,
ice->state.dirty |= IRIS_DIRTY_CC_VIEWPORT;
}
+/**
+ * The pipe->set_framebuffer_state() driver hook.
+ *
+ * Sets the current draw FBO, including color render targets, depth,
+ * and stencil buffers.
+ */
static void
iris_set_framebuffer_state(struct pipe_context *ctx,
const struct pipe_framebuffer_state *state)
ice->state.dirty |= ice->state.dirty_for_nos[IRIS_NOS_FRAMEBUFFER];
}
+/**
+ * The pipe->set_constant_buffer() driver hook.
+ *
+ * This uploads any constant data in user buffers, and references
+ * any UBO resources containing constant data.
+ */
static void
iris_set_constant_buffer(struct pipe_context *ctx,
enum pipe_shader_type p_stage, unsigned index,
ice->state.dirty |= IRIS_DIRTY_BINDINGS_VS << stage;
}
+/**
+ * The pipe->set_shader_buffers() driver hook.
+ *
+ * This binds SSBOs and ABOs. Unfortunately, we need to stream out
+ * SURFACE_STATE here, as the buffer offset may change each time.
+ */
static void
iris_set_shader_buffers(struct pipe_context *ctx,
enum pipe_shader_type p_stage,
ice->state.dirty |= IRIS_DIRTY_BINDINGS_VS << stage;
}
-static void
-iris_sampler_view_destroy(struct pipe_context *ctx,
- struct pipe_sampler_view *state)
-{
- struct iris_sampler_view *isv = (void *) state;
- pipe_resource_reference(&state->texture, NULL);
- pipe_resource_reference(&isv->surface_state.res, NULL);
- free(isv);
-}
-
-
-static void
-iris_surface_destroy(struct pipe_context *ctx, struct pipe_surface *p_surf)
-{
- struct iris_surface *surf = (void *) p_surf;
- pipe_resource_reference(&p_surf->texture, NULL);
- pipe_resource_reference(&surf->surface_state.res, NULL);
- free(surf);
-}
-
static void
iris_delete_state(struct pipe_context *ctx, void *state)
{
pipe_resource_reference(&cso->resources[i], NULL);
}
+/**
+ * The pipe->set_vertex_buffers() driver hook.
+ *
+ * This translates pipe_vertex_buffer to our 3DSTATE_VERTEX_BUFFERS packet.
+ */
static void
iris_set_vertex_buffers(struct pipe_context *ctx,
unsigned start_slot, unsigned count,
ice->state.dirty |= IRIS_DIRTY_VERTEX_BUFFERS;
}
+/**
+ * Gallium CSO for vertex elements.
+ */
struct iris_vertex_element_state {
uint32_t vertex_elements[1 + 33 * GENX(VERTEX_ELEMENT_STATE_length)];
uint32_t vf_instancing[33 * GENX(3DSTATE_VF_INSTANCING_length)];
unsigned count;
};
+/**
+ * The pipe->create_vertex_elements() driver hook.
+ *
+ * This translates pipe_vertex_element to our 3DSTATE_VERTEX_ELEMENTS
+ * and 3DSTATE_VF_INSTANCING commands. SGVs are handled at draw time.
+ */
static void *
iris_create_vertex_elements(struct pipe_context *ctx,
unsigned count,
return cso;
}
+/**
+ * The pipe->bind_vertex_elements_state() driver hook.
+ */
static void
iris_bind_vertex_elements_state(struct pipe_context *ctx, void *state)
{
struct iris_vertex_element_state *old_cso = ice->state.cso_vertex_elements;
struct iris_vertex_element_state *new_cso = state;
+ /* 3DSTATE_VF_SGVs overrides the last VE, so if the count is changing,
+ * we need to re-emit it to ensure we're overriding the right one.
+ */
if (new_cso && cso_changed(count))
ice->state.dirty |= IRIS_DIRTY_VF_SGVS;
iris_create_compute_state(struct pipe_context *ctx,
const struct pipe_compute_state *state)
{
+ // XXX: actually do something
return malloc(1);
}
+/**
+ * Gallium CSO for stream output (transform feedback) targets.
+ */
struct iris_stream_output_target {
struct pipe_stream_output_target base;
uint32_t so_buffer[GENX(3DSTATE_SO_BUFFER_length)];
+ /** Storage holding the offset where we're writing in the buffer */
struct iris_state_ref offset;
};
+/**
+ * The pipe->create_stream_output_target() driver hook.
+ *
+ * "Target" here refers to a destination buffer. We translate this into
+ * a 3DSTATE_SO_BUFFER packet. We can handle most fields, but don't yet
+ * know which buffer this represents, or whether we ought to zero the
+ * write-offsets, or append. Those are handled in the set() hook.
+ */
static struct pipe_stream_output_target *
iris_create_stream_output_target(struct pipe_context *ctx,
struct pipe_resource *res,
free(cso);
}
+/**
+ * The pipe->set_stream_output_targets() driver hook.
+ *
+ * At this point, we know which targets are bound to a particular index,
+ * and also whether we want to append or start over. We can finish the
+ * 3DSTATE_SO_BUFFER packets we started earlier.
+ */
static void
iris_set_stream_output_targets(struct pipe_context *ctx,
unsigned num_targets,
ice->state.dirty |= IRIS_DIRTY_SO_BUFFERS;
}
+/**
+ * An iris-vtable helper for encoding the 3DSTATE_SO_DECL_LIST and
+ * 3DSTATE_STREAMOUT packets.
+ *
+ * 3DSTATE_SO_DECL_LIST is a list of shader outputs we want the streamout
+ * hardware to record. We can create it entirely based on the shader, with
+ * no dynamic state dependencies.
+ *
+ * 3DSTATE_STREAMOUT is an annoying mix of shader-based information and
+ * state-based settings. We capture the shader-related ones here, and merge
+ * the rest in at draw time.
+ */
static uint32_t *
iris_create_so_decl_list(const struct pipe_stream_output_info *info,
const struct brw_vue_map *vue_map)
static void
iris_bind_compute_state(struct pipe_context *ctx, void *state)
{
+ // XXX: do something
}
+/* ------------------------------------------------------------------- */
+
+/**
+ * Set sampler-related program key fields based on the current state.
+ */
static void
iris_populate_sampler_key(const struct iris_context *ice,
struct brw_sampler_prog_key_data *key)
}
}
+/**
+ * Populate VS program key fields based on the current state.
+ */
static void
iris_populate_vs_key(const struct iris_context *ice,
struct brw_vs_prog_key *key)
iris_populate_sampler_key(ice, &key->tex);
}
+/**
+ * Populate TCS program key fields based on the current state.
+ */
static void
iris_populate_tcs_key(const struct iris_context *ice,
struct brw_tcs_prog_key *key)
iris_populate_sampler_key(ice, &key->tex);
}
+/**
+ * Populate TES program key fields based on the current state.
+ */
static void
iris_populate_tes_key(const struct iris_context *ice,
struct brw_tes_prog_key *key)
iris_populate_sampler_key(ice, &key->tex);
}
+/**
+ * Populate GS program key fields based on the current state.
+ */
static void
iris_populate_gs_key(const struct iris_context *ice,
struct brw_gs_prog_key *key)
iris_populate_sampler_key(ice, &key->tex);
}
+/**
+ * Populate FS program key fields based on the current state.
+ */
static void
iris_populate_fs_key(const struct iris_context *ice,
struct brw_wm_prog_key *key)
pkt.StatisticsEnable = true; \
pkt.Enable = true;
+/**
+ * Encode most of 3DSTATE_VS based on the compiled shader.
+ */
static void
iris_store_vs_state(const struct gen_device_info *devinfo,
struct iris_compiled_shader *shader)
}
}
+/**
+ * Encode most of 3DSTATE_HS based on the compiled shader.
+ */
static void
iris_store_tcs_state(const struct gen_device_info *devinfo,
struct iris_compiled_shader *shader)
}
}
+/**
+ * Encode 3DSTATE_TE and most of 3DSTATE_DS based on the compiled shader.
+ */
static void
iris_store_tes_state(const struct gen_device_info *devinfo,
struct iris_compiled_shader *shader)
}
+/**
+ * Encode most of 3DSTATE_GS based on the compiled shader.
+ */
static void
iris_store_gs_state(const struct gen_device_info *devinfo,
struct iris_compiled_shader *shader)
}
}
+/**
+ * Encode most of 3DSTATE_PS and 3DSTATE_PS_EXTRA based on the shader.
+ */
static void
iris_store_fs_state(const struct gen_device_info *devinfo,
struct iris_compiled_shader *shader)
}
}
+/**
+ * Compute the size of the derived data (shader command packets).
+ *
+ * This must match the data written by the iris_store_xs_state() functions.
+ */
static unsigned
iris_derived_program_state_size(enum iris_program_cache_id cache_id)
{
return sizeof(uint32_t) * dwords[cache_id];
}
+/**
+ * Create any state packets corresponding to the given shader stage
+ * (i.e. 3DSTATE_VS) and save them as "derived data" in the shader variant.
+ * This means that we can look up a program in the in-memory cache and
+ * get most of the state packet without having to reconstruct it.
+ */
static void
iris_store_derived_program_state(const struct gen_device_info *devinfo,
enum iris_program_cache_id cache_id,
}
}
+/* ------------------------------------------------------------------- */
+
+/**
+ * Configure the URB.
+ *
+ * XXX: write a real comment.
+ */
static void
iris_upload_urb_config(struct iris_context *ice, struct iris_batch *batch)
{
return surf_state->offset;
}
+/**
+ * Populate the binding table for a given shader stage.
+ *
+ * This fills out the table of pointers to surfaces required by the shader,
+ * and also adds those buffers to the validation list so the kernel can make
+ * resident before running our batch.
+ */
static void
iris_populate_binding_table(struct iris_context *ice,
struct iris_batch *batch,
const struct shader_info *info = iris_get_shader_info(ice, stage);
struct iris_shader_state *shs = &ice->shaders.state[stage];
- // Surfaces:
- // - pull constants
- // - ubos/ssbos/abos
- // - images
- // - textures
- // - render targets - write and read
-
//struct brw_stage_prog_data *prog_data = (void *) shader->prog_data;
uint32_t *bt_map = binder->map + binder->bt_offset[stage];
int s = 0;
#if 0
// XXX: not implemented yet
- assert(prog_data->binding_table.pull_constants_start == 0xd0d0d0d0);
- assert(prog_data->binding_table.ubo_start == 0xd0d0d0d0);
- assert(prog_data->binding_table.ssbo_start == 0xd0d0d0d0);
assert(prog_data->binding_table.image_start == 0xd0d0d0d0);
- assert(prog_data->binding_table.shader_time_start == 0xd0d0d0d0);
- //assert(prog_data->binding_table.plane_start[1] == 0xd0d0d0d0);
- //assert(prog_data->binding_table.plane_start[2] == 0xd0d0d0d0);
+ assert(prog_data->binding_table.plane_start[1] == 0xd0d0d0d0);
+ assert(prog_data->binding_table.plane_start[2] == 0xd0d0d0d0);
#endif
}
}
}
+/* ------------------------------------------------------------------- */
/**
* Pin any BOs which were installed by a previous batch, and restored
pipe_resource_reference(&ice->state.last_res.blend, NULL);
}
+/* ------------------------------------------------------------------- */
+
static unsigned
flags_to_post_sync_op(uint32_t flags)
{
*
* Synchronization of the 3D Pipeline > PIPE_CONTROL Command > Programming
* Restrictions for PIPE_CONTROL.
+ *
+ * You should not use this function directly. Use the helpers in
+ * iris_pipe_control.c instead, which may split the pipe control further.
*/
static void
iris_emit_raw_pipe_control(struct iris_batch *batch, uint32_t flags,