+ unsigned inverted_texcoords = emit->inverted_texcoords;
+
+ while (inverted_texcoords) {
+ const unsigned unit = ffs(inverted_texcoords) - 1;
+
+ assert(emit->inverted_texcoords & (1 << unit));
+
+ assert(unit < ARRAY_SIZE(emit->ps_true_texcoord));
+
+ assert(unit < ARRAY_SIZE(emit->ps_inverted_texcoord_input));
+
+ assert(emit->ps_inverted_texcoord_input[unit]
+ < ARRAY_SIZE(emit->input_map));
+
+ /* inverted = coord * (1, -1, 1, 1) + (0, 1, 0, 0) */
+ if (!submit_op3(emit,
+ inst_token(SVGA3DOP_MAD),
+ dst(emit->ps_inverted_texcoord[unit]),
+ emit->ps_true_texcoord[unit],
+ get_immediate(emit, 1.0f, -1.0f, 1.0f, 1.0f),
+ get_immediate(emit, 0.0f, 1.0f, 0.0f, 0.0f)))
+ return FALSE;
+
+ /* Reassign the input_map entry to the new texcoord register */
+ emit->input_map[emit->ps_inverted_texcoord_input[unit]] =
+ emit->ps_inverted_texcoord[unit];
+
+ inverted_texcoords &= ~(1 << unit);
+ }
+
+ return TRUE;
+}
+
+
+/**
+ * Emit code to adjust vertex shader inputs/attributes:
+ * - Change range from [0,1] to [-1,1] (for normalized byte/short attribs).
+ * - Set attrib W component = 1.
+ */
+static boolean
+emit_adjusted_vertex_attribs(struct svga_shader_emitter *emit)
+{
+ unsigned adjust_mask = (emit->key.vs.adjust_attrib_range |
+ emit->key.vs.adjust_attrib_w_1);
+
+ while (adjust_mask) {
+ /* Adjust vertex attrib range and/or set W component = 1 */
+ const unsigned index = u_bit_scan(&adjust_mask);
+ struct src_register tmp;
+
+ /* allocate a temp reg */
+ tmp = src_register(SVGA3DREG_TEMP, emit->nr_hw_temp);
+ emit->nr_hw_temp++;
+
+ if (emit->key.vs.adjust_attrib_range & (1 << index)) {
+ /* The vertex input/attribute is supposed to be a signed value in
+ * the range [-1,1] but we actually fetched/converted it to the
+ * range [0,1]. This most likely happens when the app specifies a
+ * signed byte attribute but we interpreted it as unsigned bytes.
+ * See also svga_translate_vertex_format().
+ *
+ * Here, we emit some extra instructions to adjust
+ * the attribute values from [0,1] to [-1,1].
+ *
+ * The adjustment we implement is:
+ * new_attrib = attrib * 2.0;
+ * if (attrib >= 0.5)
+ * new_attrib = new_attrib - 2.0;
+ * This isn't exactly right (it's off by a bit or so) but close enough.
+ */
+ SVGA3dShaderDestToken pred_reg = dst_register(SVGA3DREG_PREDICATE, 0);
+
+ /* tmp = attrib * 2.0 */
+ if (!submit_op2(emit,
+ inst_token(SVGA3DOP_MUL),
+ dst(tmp),
+ emit->input_map[index],
+ get_two_immediate(emit)))
+ return FALSE;
+
+ /* pred = (attrib >= 0.5) */
+ if (!submit_op2(emit,
+ inst_token_setp(SVGA3DOPCOMP_GE),
+ pred_reg,
+ emit->input_map[index], /* vert attrib */
+ get_half_immediate(emit))) /* 0.5 */
+ return FALSE;
+
+ /* sub(pred) tmp, tmp, 2.0 */
+ if (!submit_op3(emit,
+ inst_token_predicated(SVGA3DOP_SUB),
+ dst(tmp),
+ src(pred_reg),
+ tmp,
+ get_two_immediate(emit)))
+ return FALSE;
+ }
+ else {
+ /* just copy the vertex input attrib to the temp register */
+ if (!submit_op1(emit,
+ inst_token(SVGA3DOP_MOV),
+ dst(tmp),
+ emit->input_map[index]))
+ return FALSE;
+ }
+
+ if (emit->key.vs.adjust_attrib_w_1 & (1 << index)) {
+ /* move 1 into W position of tmp */
+ if (!submit_op1(emit,
+ inst_token(SVGA3DOP_MOV),
+ writemask(dst(tmp), TGSI_WRITEMASK_W),
+ get_one_immediate(emit)))
+ return FALSE;
+ }
+
+ /* Reassign the input_map entry to the new tmp register */
+ emit->input_map[index] = tmp;
+ }
+
+ return TRUE;
+}