/*
 * texmip_sim.c — host-runnable proof for DF-4032.
 *
 * Replicates r600_mip_minify()/r600_texture_size()
 * (sys/dev/drm/radeon/r600_cs.c:1399-1457) for the PoC texture:
 *   512x512, COLOR_8 (1 byte/px), blevel=0, llevel=9, nfaces=1,
 *   nsamples=1, pitch_align=1 (linear), height_align=1, base_align=1
 * and shows mipmap_size >> 256-byte mipmap BO while the only check that
 * would catch it (r600_cs.c:1603-1606) is commented out.
 */
#include <stdio.h>
#include <stdint.h>

static unsigned mip_minify(unsigned size, unsigned level)
{
	unsigned val = size >> level;
	if (val == 0) val = 1;
	if (level > 0) { /* roundup_pow_of_two */
		unsigned v = 1; while (v < val) v <<= 1;
		val = v;
	}
	return val;
}

int main(void)
{
	unsigned w0 = 512, h0 = 512, d0 = 1, blevel = 0, llevel = 9;
	unsigned blocksize = 1, nsamples = 1, nfaces = 1;
	unsigned block_align = 1, height_align = 1, base_align = 1;
	unsigned offset = 0, level, i;
	unsigned l0_size = (unsigned)-1, mipmap_size;

	for (i = 0, level = blevel; i <= llevel - blevel; i++, level++) {
		unsigned width = mip_minify(w0, i);
		unsigned nbx = width;             /* nblocksx for 1x1 blocks */
		unsigned height = mip_minify(h0, i);
		unsigned nby = height;
		unsigned depth = mip_minify(d0, i);
		unsigned size = nbx * nby * blocksize * nsamples;
		size *= nfaces ? nfaces : depth;
		if (i == 0) l0_size = size;
		if (i == 0 || i == 1) offset = offset; /* round_up(0,1)=0 */
		offset += size;
		printf("level %u: %ux%u -> %u bytes (offset %u)\n",
		       level, width, height, size, offset);
	}
	mipmap_size = offset;
	if (llevel == 0) mipmap_size = l0_size;
	if (!blevel) mipmap_size -= l0_size;

	printf("\nl0_size      = %u (checked vs 1 MiB texture BO: PASS)\n", l0_size);
	printf("mipmap_size  = %u vs 256-byte mipmap BO\n", mipmap_size);
	printf("r600_cs.c:1603 check is COMMENTED OUT -> submission ACCEPTED;\n"
	       "GPU mip walks %u bytes past a 256-byte BO.\n", mipmap_size - 256);
	return 0;
}
