static bool
check_tmu_write(struct vc4_validated_shader_info *validated_shader,
		struct vc4_shader_validation_state *validation_state,
		uint32_t waddr)
{
	int tmu = waddr > QPU_W_TMU0_B;

	if (!is_tmu_write(waddr))
		return true;

	if (validation_state->tmu_write_count[tmu] >= 4) {
		DRM_ERROR("TMU%d got too many parameters before dispatch\n",
			  tmu);
		return false;
	}
	validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] =
		validated_shader->uniforms_size;
	validation_state->tmu_write_count[tmu]++;
	validated_shader->uniforms_size += 4;

	if (waddr == QPU_W_TMU0_S || waddr == QPU_W_TMU1_S) {
		if (!record_validated_texture_sample(validated_shader,
						     validation_state, tmu)) {
			return false;
		}

		validation_state->tmu_write_count[tmu] = 0;
	}

	return true;
}
Example #2
0
static bool
check_tmu_write(uint64_t inst,
		struct vc4_validated_shader_info *validated_shader,
		struct vc4_shader_validation_state *validation_state,
		bool is_mul)
{
	uint32_t waddr = (is_mul ?
			  QPU_GET_FIELD(inst, QPU_WADDR_MUL) :
			  QPU_GET_FIELD(inst, QPU_WADDR_ADD));
	uint32_t raddr_a = QPU_GET_FIELD(inst, QPU_RADDR_A);
	uint32_t raddr_b = QPU_GET_FIELD(inst, QPU_RADDR_B);
	int tmu = waddr > QPU_W_TMU0_B;
	bool submit = is_tmu_submit(waddr);
	bool is_direct = submit && validation_state->tmu_write_count[tmu] == 0;
	uint32_t sig = QPU_GET_FIELD(inst, QPU_SIG);

	if (is_direct) {
		uint32_t add_b = QPU_GET_FIELD(inst, QPU_ADD_B);
		uint32_t clamp_reg, clamp_offset;

		if (sig == QPU_SIG_SMALL_IMM) {
			DRM_ERROR("direct TMU read used small immediate\n");
			return false;
		}

		/* Make sure that this texture load is an add of the base
		 * address of the UBO to a clamped offset within the UBO.
		 */
		if (is_mul ||
		    QPU_GET_FIELD(inst, QPU_OP_ADD) != QPU_A_ADD) {
			DRM_ERROR("direct TMU load wasn't an add\n");
			return false;
		}

		/* We assert that the the clamped address is the first
		 * argument, and the UBO base address is the second argument.
		 * This is arbitrary, but simpler than supporting flipping the
		 * two either way.
		 */
		clamp_reg = raddr_add_a_to_live_reg_index(inst);
		if (clamp_reg == ~0) {
			DRM_ERROR("direct TMU load wasn't clamped\n");
			return false;
		}

		clamp_offset = validation_state->live_min_clamp_offsets[clamp_reg];
		if (clamp_offset == ~0) {
			DRM_ERROR("direct TMU load wasn't clamped\n");
			return false;
		}

		/* Store the clamp value's offset in p1 (see reloc_tex() in
		 * vc4_validate.c).
		 */
		validation_state->tmu_setup[tmu].p_offset[1] =
			clamp_offset;

		if (!(add_b == QPU_MUX_A && raddr_a == QPU_R_UNIF) &&
		    !(add_b == QPU_MUX_B && raddr_b == QPU_R_UNIF)) {
			DRM_ERROR("direct TMU load didn't add to a uniform\n");
			return false;
		}

		validation_state->tmu_setup[tmu].is_direct = true;
	} else {
		if (raddr_a == QPU_R_UNIF || (sig != QPU_SIG_SMALL_IMM &&
					      raddr_b == QPU_R_UNIF)) {
			DRM_ERROR("uniform read in the same instruction as "
				  "texture setup.\n");
			return false;
		}
	}

	if (validation_state->tmu_write_count[tmu] >= 4) {
		DRM_ERROR("TMU%d got too many parameters before dispatch\n",
			  tmu);
		return false;
	}
	validation_state->tmu_setup[tmu].p_offset[validation_state->tmu_write_count[tmu]] =
		validated_shader->uniforms_size;
	validation_state->tmu_write_count[tmu]++;
	/* Since direct uses a RADDR uniform reference, it will get counted in
	 * check_instruction_reads()
	 */
	if (!is_direct)
		validated_shader->uniforms_size += 4;

	if (submit) {
		if (!record_validated_texture_sample(validated_shader,
						     validation_state, tmu)) {
			return false;
		}

		validation_state->tmu_write_count[tmu] = 0;
	}

	return true;
}