unsigned r300_get_swizzle_combined(const unsigned char *swizzle_format, const unsigned char *swizzle_view, boolean dxtc_swizzle) { unsigned i; unsigned char swizzle[4]; unsigned result = 0; const uint32_t swizzle_shift[4] = { R300_TX_FORMAT_R_SHIFT, R300_TX_FORMAT_G_SHIFT, R300_TX_FORMAT_B_SHIFT, R300_TX_FORMAT_A_SHIFT }; uint32_t swizzle_bit[4] = { dxtc_swizzle ? R300_TX_FORMAT_Z : R300_TX_FORMAT_X, R300_TX_FORMAT_Y, dxtc_swizzle ? R300_TX_FORMAT_X : R300_TX_FORMAT_Z, R300_TX_FORMAT_W }; if (swizzle_view) { /* Combine two sets of swizzles. */ util_format_compose_swizzles(swizzle_format, swizzle_view, swizzle); } else { memcpy(swizzle, swizzle_format, 4); } /* Get swizzle. */ for (i = 0; i < 4; i++) { switch (swizzle[i]) { case UTIL_FORMAT_SWIZZLE_Y: result |= swizzle_bit[1] << swizzle_shift[i]; break; case UTIL_FORMAT_SWIZZLE_Z: result |= swizzle_bit[2] << swizzle_shift[i]; break; case UTIL_FORMAT_SWIZZLE_W: result |= swizzle_bit[3] << swizzle_shift[i]; break; case UTIL_FORMAT_SWIZZLE_0: result |= R300_TX_FORMAT_ZERO << swizzle_shift[i]; break; case UTIL_FORMAT_SWIZZLE_1: result |= R300_TX_FORMAT_ONE << swizzle_shift[i]; break; default: /* UTIL_FORMAT_SWIZZLE_X */ result |= swizzle_bit[0] << swizzle_shift[i]; } } return result; }
uint32_t fd4_tex_swiz(enum pipe_format format, unsigned swizzle_r, unsigned swizzle_g, unsigned swizzle_b, unsigned swizzle_a) { const struct util_format_description *desc = util_format_description(format); unsigned char swiz[4] = { swizzle_r, swizzle_g, swizzle_b, swizzle_a, }, rswiz[4]; util_format_compose_swizzles(desc->swizzle, swiz, rswiz); return A4XX_TEX_CONST_0_SWIZ_X(tex_swiz(rswiz[0])) | A4XX_TEX_CONST_0_SWIZ_Y(tex_swiz(rswiz[1])) | A4XX_TEX_CONST_0_SWIZ_Z(tex_swiz(rswiz[2])) | A4XX_TEX_CONST_0_SWIZ_W(tex_swiz(rswiz[3])); }
static void * vc5_vertex_state_create(struct pipe_context *pctx, unsigned num_elements, const struct pipe_vertex_element *elements) { struct vc5_context *vc5 = vc5_context(pctx); struct vc5_vertex_stateobj *so = CALLOC_STRUCT(vc5_vertex_stateobj); if (!so) return NULL; memcpy(so->pipe, elements, sizeof(*elements) * num_elements); so->num_elements = num_elements; for (int i = 0; i < so->num_elements; i++) { const struct pipe_vertex_element *elem = &elements[i]; const struct util_format_description *desc = util_format_description(elem->src_format); uint32_t r_size = desc->channel[0].size; struct V3D33_GL_SHADER_STATE_ATTRIBUTE_RECORD attr_unpacked = { /* vec_size == 0 means 4 */ .vec_size = desc->nr_channels & 3, .signed_int_type = (desc->channel[0].type == UTIL_FORMAT_TYPE_SIGNED), .normalized_int_type = desc->channel[0].normalized, .read_as_int_uint = desc->channel[0].pure_integer, .instance_divisor = elem->instance_divisor, }; switch (desc->channel[0].type) { case UTIL_FORMAT_TYPE_FLOAT: if (r_size == 32) { attr_unpacked.type = ATTRIBUTE_FLOAT; } else { assert(r_size == 16); attr_unpacked.type = ATTRIBUTE_HALF_FLOAT; } break; case UTIL_FORMAT_TYPE_SIGNED: case UTIL_FORMAT_TYPE_UNSIGNED: switch (r_size) { case 32: attr_unpacked.type = ATTRIBUTE_INT; break; case 16: attr_unpacked.type = ATTRIBUTE_SHORT; break; case 10: attr_unpacked.type = ATTRIBUTE_INT2_10_10_10; break; case 8: attr_unpacked.type = ATTRIBUTE_BYTE; break; default: fprintf(stderr, "format %s unsupported\n", desc->name); attr_unpacked.type = ATTRIBUTE_BYTE; abort(); } break; default: fprintf(stderr, "format %s unsupported\n", desc->name); abort(); } const uint32_t size = cl_packet_length(GL_SHADER_STATE_ATTRIBUTE_RECORD); V3D33_GL_SHADER_STATE_ATTRIBUTE_RECORD_pack(NULL, (uint8_t *)&so->attrs[i * size], &attr_unpacked); } /* Set up the default attribute values in case any of the vertex * elements use them. */ so->default_attribute_values = vc5_bo_alloc(vc5->screen, VC5_MAX_ATTRIBUTES * 4 * sizeof(float), "default attributes"); uint32_t *attrs = vc5_bo_map(so->default_attribute_values); for (int i = 0; i < VC5_MAX_ATTRIBUTES; i++) { attrs[i * 4 + 0] = 0; attrs[i * 4 + 1] = 0; attrs[i * 4 + 2] = 0; if (i < so->num_elements && util_format_is_pure_integer(so->pipe[i].src_format)) { attrs[i * 4 + 3] = 1; } else { attrs[i * 4 + 3] = fui(1.0); } } return so; } static void vc5_vertex_state_bind(struct pipe_context *pctx, void *hwcso) { struct vc5_context *vc5 = vc5_context(pctx); vc5->vtx = hwcso; vc5->dirty |= VC5_DIRTY_VTXSTATE; } static void vc5_set_constant_buffer(struct pipe_context *pctx, uint shader, uint index, const struct pipe_constant_buffer *cb) { struct vc5_context *vc5 = vc5_context(pctx); struct vc5_constbuf_stateobj *so = &vc5->constbuf[shader]; util_copy_constant_buffer(&so->cb[index], cb); /* Note that the state tracker can unbind constant buffers by * passing NULL here. */ if (unlikely(!cb)) { so->enabled_mask &= ~(1 << index); so->dirty_mask &= ~(1 << index); return; } so->enabled_mask |= 1 << index; so->dirty_mask |= 1 << index; vc5->dirty |= VC5_DIRTY_CONSTBUF; } static void vc5_set_framebuffer_state(struct pipe_context *pctx, const struct pipe_framebuffer_state *framebuffer) { struct vc5_context *vc5 = vc5_context(pctx); struct pipe_framebuffer_state *cso = &vc5->framebuffer; unsigned i; vc5->job = NULL; for (i = 0; i < framebuffer->nr_cbufs; i++) pipe_surface_reference(&cso->cbufs[i], framebuffer->cbufs[i]); for (; i < vc5->framebuffer.nr_cbufs; i++) pipe_surface_reference(&cso->cbufs[i], NULL); cso->nr_cbufs = framebuffer->nr_cbufs; pipe_surface_reference(&cso->zsbuf, framebuffer->zsbuf); cso->width = framebuffer->width; cso->height = framebuffer->height; vc5->dirty |= VC5_DIRTY_FRAMEBUFFER; } static struct vc5_texture_stateobj * vc5_get_stage_tex(struct vc5_context *vc5, enum pipe_shader_type shader) { switch (shader) { case PIPE_SHADER_FRAGMENT: vc5->dirty |= VC5_DIRTY_FRAGTEX; return &vc5->fragtex; break; case PIPE_SHADER_VERTEX: vc5->dirty |= VC5_DIRTY_VERTTEX; return &vc5->verttex; break; default: fprintf(stderr, "Unknown shader target %d\n", shader); abort(); } } static uint32_t translate_wrap(uint32_t pipe_wrap, bool using_nearest) { switch (pipe_wrap) { case PIPE_TEX_WRAP_REPEAT: return 0; case PIPE_TEX_WRAP_CLAMP_TO_EDGE: return 1; case PIPE_TEX_WRAP_MIRROR_REPEAT: return 2; case PIPE_TEX_WRAP_CLAMP_TO_BORDER: return 3; case PIPE_TEX_WRAP_CLAMP: return (using_nearest ? 1 : 3); default: unreachable("Unknown wrap mode"); } } static void * vc5_create_sampler_state(struct pipe_context *pctx, const struct pipe_sampler_state *cso) { struct vc5_sampler_state *so = CALLOC_STRUCT(vc5_sampler_state); if (!so) return NULL; memcpy(so, cso, sizeof(*cso)); bool either_nearest = (cso->mag_img_filter == PIPE_TEX_MIPFILTER_NEAREST || cso->min_img_filter == PIPE_TEX_MIPFILTER_NEAREST); struct V3D33_TEXTURE_UNIFORM_PARAMETER_0_CFG_MODE1 p0_unpacked = { .s_wrap_mode = translate_wrap(cso->wrap_s, either_nearest), .t_wrap_mode = translate_wrap(cso->wrap_t, either_nearest), .r_wrap_mode = translate_wrap(cso->wrap_r, either_nearest), }; V3D33_TEXTURE_UNIFORM_PARAMETER_0_CFG_MODE1_pack(NULL, (uint8_t *)&so->p0, &p0_unpacked); struct V3D33_TEXTURE_SHADER_STATE state_unpacked = { cl_packet_header(TEXTURE_SHADER_STATE), .min_level_of_detail = MAX2(cso->min_lod, 0.0), .depth_compare_function = cso->compare_func, .fixed_bias = cso->lod_bias, }; STATIC_ASSERT(ARRAY_SIZE(so->texture_shader_state) == cl_packet_length(TEXTURE_SHADER_STATE)); cl_packet_pack(TEXTURE_SHADER_STATE)(NULL, so->texture_shader_state, &state_unpacked); return so; } static void vc5_sampler_states_bind(struct pipe_context *pctx, enum pipe_shader_type shader, unsigned start, unsigned nr, void **hwcso) { struct vc5_context *vc5 = vc5_context(pctx); struct vc5_texture_stateobj *stage_tex = vc5_get_stage_tex(vc5, shader); assert(start == 0); unsigned i; unsigned new_nr = 0; for (i = 0; i < nr; i++) { if (hwcso[i]) new_nr = i + 1; stage_tex->samplers[i] = hwcso[i]; } for (; i < stage_tex->num_samplers; i++) { stage_tex->samplers[i] = NULL; } stage_tex->num_samplers = new_nr; } static uint32_t translate_swizzle(unsigned char pipe_swizzle) { switch (pipe_swizzle) { case PIPE_SWIZZLE_0: return 0; case PIPE_SWIZZLE_1: return 1; case PIPE_SWIZZLE_X: case PIPE_SWIZZLE_Y: case PIPE_SWIZZLE_Z: case PIPE_SWIZZLE_W: return 2 + pipe_swizzle; default: unreachable("unknown swizzle"); } } static struct pipe_sampler_view * vc5_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *prsc, const struct pipe_sampler_view *cso) { struct vc5_sampler_view *so = CALLOC_STRUCT(vc5_sampler_view); struct vc5_resource *rsc = vc5_resource(prsc); if (!so) return NULL; so->base = *cso; pipe_reference(NULL, &prsc->reference); struct V3D33_TEXTURE_UNIFORM_PARAMETER_1_CFG_MODE1 unpacked = { }; unpacked.return_word_0_of_texture_data = true; if (vc5_get_tex_return_size(cso->format) == 16) { unpacked.return_word_1_of_texture_data = true; } else { int chans = vc5_get_tex_return_channels(cso->format); if (chans > 1) unpacked.return_word_1_of_texture_data = true; if (chans > 2) unpacked.return_word_2_of_texture_data = true; if (chans > 3) unpacked.return_word_3_of_texture_data = true; } V3D33_TEXTURE_UNIFORM_PARAMETER_1_CFG_MODE1_pack(NULL, (uint8_t *)&so->p1, &unpacked); /* Compute the sampler view's swizzle up front. This will be plugged * into either the sampler (for 16-bit returns) or the shader's * texture key (for 32) */ uint8_t view_swizzle[4] = { cso->swizzle_r, cso->swizzle_g, cso->swizzle_b, cso->swizzle_a }; const uint8_t *fmt_swizzle = vc5_get_format_swizzle(so->base.format); util_format_compose_swizzles(fmt_swizzle, view_swizzle, so->swizzle); so->base.texture = prsc; so->base.reference.count = 1; so->base.context = pctx; struct V3D33_TEXTURE_SHADER_STATE state_unpacked = { cl_packet_header(TEXTURE_SHADER_STATE), .image_width = prsc->width0, .image_height = prsc->height0, .image_depth = prsc->depth0, .texture_type = rsc->tex_format, .srgb = util_format_is_srgb(cso->format), .base_level = cso->u.tex.first_level, .array_stride_64_byte_aligned = rsc->cube_map_stride / 64, }; /* Note: Contrary to the docs, the swizzle still applies even * if the return size is 32. It's just that you probably want * to swizzle in the shader, because you need the Y/Z/W * channels to be defined. */ if (vc5_get_tex_return_size(cso->format) != 32) { state_unpacked.swizzle_r = translate_swizzle(so->swizzle[0]); state_unpacked.swizzle_g = translate_swizzle(so->swizzle[1]); state_unpacked.swizzle_b = translate_swizzle(so->swizzle[2]); state_unpacked.swizzle_a = translate_swizzle(so->swizzle[3]); } else { state_unpacked.swizzle_r = translate_swizzle(PIPE_SWIZZLE_X); state_unpacked.swizzle_g = translate_swizzle(PIPE_SWIZZLE_Y); state_unpacked.swizzle_b = translate_swizzle(PIPE_SWIZZLE_Z); state_unpacked.swizzle_a = translate_swizzle(PIPE_SWIZZLE_W); } /* XXX: While we need to use this flag to enable tiled * resource sharing (even a small shared buffer should be UIF, * not UBLINEAR or raster), this is also at the moment * patching up the fact that our resource layout's decisions * about XOR don't quite match the HW's. */ switch (rsc->slices[0].tiling) { case VC5_TILING_UIF_NO_XOR: case VC5_TILING_UIF_XOR: state_unpacked.level_0_is_strictly_uif = true; state_unpacked.level_0_xor_enable = false; break; default: break; } STATIC_ASSERT(ARRAY_SIZE(so->texture_shader_state) == cl_packet_length(TEXTURE_SHADER_STATE)); cl_packet_pack(TEXTURE_SHADER_STATE)(NULL, so->texture_shader_state, &state_unpacked); return &so->base; } static void vc5_sampler_view_destroy(struct pipe_context *pctx, struct pipe_sampler_view *view) { pipe_resource_reference(&view->texture, NULL); free(view); } static void vc5_set_sampler_views(struct pipe_context *pctx, enum pipe_shader_type shader, unsigned start, unsigned nr, struct pipe_sampler_view **views) { struct vc5_context *vc5 = vc5_context(pctx); struct vc5_texture_stateobj *stage_tex = vc5_get_stage_tex(vc5, shader); unsigned i; unsigned new_nr = 0; assert(start == 0); for (i = 0; i < nr; i++) { if (views[i]) new_nr = i + 1; pipe_sampler_view_reference(&stage_tex->textures[i], views[i]); } for (; i < stage_tex->num_textures; i++) { pipe_sampler_view_reference(&stage_tex->textures[i], NULL); } stage_tex->num_textures = new_nr; } static struct pipe_stream_output_target * vc5_create_stream_output_target(struct pipe_context *pctx, struct pipe_resource *prsc, unsigned buffer_offset, unsigned buffer_size) { struct pipe_stream_output_target *target; target = CALLOC_STRUCT(pipe_stream_output_target); if (!target) return NULL; pipe_reference_init(&target->reference, 1); pipe_resource_reference(&target->buffer, prsc); target->context = pctx; target->buffer_offset = buffer_offset; target->buffer_size = buffer_size; return target; } static void vc5_stream_output_target_destroy(struct pipe_context *pctx, struct pipe_stream_output_target *target) { pipe_resource_reference(&target->buffer, NULL); free(target); }
static void get_external_state( struct r300_context* r300, struct r300_fragment_program_external_state* state) { struct r300_textures_state *texstate = r300->textures_state.state; struct r300_rs_state *rs = r300->rs_state.state; unsigned i; state->frag_clamp = rs ? rs->rs.clamp_fragment_color : 0; for (i = 0; i < texstate->sampler_state_count; i++) { struct r300_sampler_state *s = texstate->sampler_states[i]; struct r300_sampler_view *v = texstate->sampler_views[i]; struct r300_resource *t; if (!s || !v) { continue; } t = r300_resource(v->base.texture); if (s->state.compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { state->unit[i].compare_mode_enabled = 1; /* Fortunately, no need to translate this. */ state->unit[i].texture_compare_func = s->state.compare_func; } state->unit[i].non_normalized_coords = !s->state.normalized_coords; state->unit[i].convert_unorm_to_snorm = v->base.format == PIPE_FORMAT_RGTC1_SNORM || v->base.format == PIPE_FORMAT_LATC1_SNORM; /* Pass texture swizzling to the compiler, some lowering passes need it. */ if (v->base.format == PIPE_FORMAT_RGTC1_SNORM || v->base.format == PIPE_FORMAT_LATC1_SNORM) { unsigned char swizzle[4]; util_format_compose_swizzles( util_format_description(v->base.format)->swizzle, v->swizzle, swizzle); state->unit[i].texture_swizzle = RC_MAKE_SWIZZLE(swizzle[0], swizzle[1], swizzle[2], swizzle[3]); } else if (state->unit[i].compare_mode_enabled) { state->unit[i].texture_swizzle = RC_MAKE_SWIZZLE(v->swizzle[0], v->swizzle[1], v->swizzle[2], v->swizzle[3]); } /* XXX this should probably take into account STR, not just S. */ if (t->tex.is_npot) { switch (s->state.wrap_s) { case PIPE_TEX_WRAP_REPEAT: state->unit[i].wrap_mode = RC_WRAP_REPEAT; break; case PIPE_TEX_WRAP_MIRROR_REPEAT: state->unit[i].wrap_mode = RC_WRAP_MIRRORED_REPEAT; break; case PIPE_TEX_WRAP_MIRROR_CLAMP: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_EDGE: case PIPE_TEX_WRAP_MIRROR_CLAMP_TO_BORDER: state->unit[i].wrap_mode = RC_WRAP_MIRRORED_CLAMP; break; default: state->unit[i].wrap_mode = RC_WRAP_NONE; } if (t->b.b.b.target == PIPE_TEXTURE_3D) state->unit[i].clamp_and_scale_before_fetch = TRUE; } } }