#include "nvfx_context.h" #include "nvfx_resource.h" #include "nouveau/nouveau_util.h" void nvfx_state_framebuffer_validate(struct nvfx_context *nvfx) { struct pipe_framebuffer_state *fb = &nvfx->framebuffer; struct nouveau_channel *chan = nvfx->screen->base.channel; uint32_t rt_enable = 0, rt_format = 0; int i, colour_format = 0, zeta_format = 0; int depth_only = 0; unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM; unsigned w = fb->width; unsigned h = fb->height; int colour_bits = 32, zeta_bits = 32; if(!nvfx->is_nv4x) assert(fb->nr_cbufs <= 2); else assert(fb->nr_cbufs <= 4); for (i = 0; i < fb->nr_cbufs; i++) { if (colour_format) assert(colour_format == fb->cbufs[i]->format); else colour_format = fb->cbufs[i]->format; rt_enable |= (NV34TCL_RT_ENABLE_COLOR0 << i); nvfx->hw_rt[i].bo = nvfx_surface_buffer(fb->cbufs[i]); nvfx->hw_rt[i].offset = fb->cbufs[i]->offset; nvfx->hw_rt[i].pitch = ((struct nv04_surface *)fb->cbufs[i])->pitch; } for(; i < 4; ++i) nvfx->hw_rt[i].bo = 0; if (rt_enable & (NV34TCL_RT_ENABLE_COLOR1 | NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3)) rt_enable |= NV34TCL_RT_ENABLE_MRT; if (fb->zsbuf) { zeta_format = fb->zsbuf->format; nvfx->hw_zeta.bo = nvfx_surface_buffer(fb->zsbuf); nvfx->hw_zeta.offset = fb->zsbuf->offset; nvfx->hw_zeta.pitch = ((struct nv04_surface *)fb->zsbuf)->pitch; } else nvfx->hw_zeta.bo = 0; if (rt_enable & (NV34TCL_RT_ENABLE_COLOR0 | NV34TCL_RT_ENABLE_COLOR1 | NV40TCL_RT_ENABLE_COLOR2 | NV40TCL_RT_ENABLE_COLOR3)) { /* Render to at least a colour buffer */ if (!(fb->cbufs[0]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)) { assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); for (i = 1; i < fb->nr_cbufs; i++) assert(!(fb->cbufs[i]->texture->flags & NVFX_RESOURCE_FLAG_LINEAR)); rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | (log2i(fb->cbufs[0]->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) | (log2i(fb->cbufs[0]->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT); } else rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR; } else if (fb->zsbuf) { depth_only = 1; /* Render to depth buffer only */ if (!(fb->zsbuf->texture->usage & NVFX_RESOURCE_FLAG_LINEAR)) { assert(!(fb->width & (fb->width - 1)) && !(fb->height & (fb->height - 1))); rt_format = NV34TCL_RT_FORMAT_TYPE_SWIZZLED | (log2i(fb->zsbuf->width) << NV34TCL_RT_FORMAT_LOG2_WIDTH_SHIFT) | (log2i(fb->zsbuf->height) << NV34TCL_RT_FORMAT_LOG2_HEIGHT_SHIFT); } else rt_format = NV34TCL_RT_FORMAT_TYPE_LINEAR; } else { return; } switch (colour_format) { case PIPE_FORMAT_B8G8R8X8_UNORM: rt_format |= NV34TCL_RT_FORMAT_COLOR_X8R8G8B8; break; case PIPE_FORMAT_B8G8R8A8_UNORM: case 0: rt_format |= NV34TCL_RT_FORMAT_COLOR_A8R8G8B8; break; case PIPE_FORMAT_B5G6R5_UNORM: rt_format |= NV34TCL_RT_FORMAT_COLOR_R5G6B5; colour_bits = 16; break; default: assert(0); } switch (zeta_format) { case PIPE_FORMAT_Z16_UNORM: rt_format |= NV34TCL_RT_FORMAT_ZETA_Z16; zeta_bits = 16; break; case PIPE_FORMAT_S8_USCALED_Z24_UNORM: case PIPE_FORMAT_X8Z24_UNORM: case 0: rt_format |= NV34TCL_RT_FORMAT_ZETA_Z24S8; break; default: assert(0); } if ((!nvfx->is_nv4x) && colour_bits > zeta_bits) { /* TODO: does this limitation really exist? TODO: can it be worked around somehow? */ assert(0); } if ((rt_enable & NV34TCL_RT_ENABLE_COLOR0) || ((!nvfx->is_nv4x) && depth_only)) { struct nvfx_render_target *rt0 = (depth_only ? &nvfx->hw_zeta : &nvfx->hw_rt[0]); uint32_t pitch = rt0->pitch; if(!nvfx->is_nv4x) { if (nvfx->hw_zeta.bo) { pitch |= (nvfx->hw_zeta.pitch << 16); } else { pitch |= (pitch << 16); } } OUT_RING(chan, RING_3D(NV34TCL_DMA_COLOR0, 1)); OUT_RELOC(chan, rt0->bo, 0, rt_flags | NOUVEAU_BO_OR, chan->vram->handle, chan->gart->handle); OUT_RING(chan, RING_3D(NV34TCL_COLOR0_PITCH, 2)); OUT_RING(chan, pitch); OUT_RELOC(chan, rt0->bo, rt0->offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); } if (rt_enable & NV34TCL_RT_ENABLE_COLOR1) { OUT_RING(chan, RING_3D(NV34TCL_DMA_COLOR1, 1)); OUT_RELOC(chan, nvfx->hw_rt[1].bo, 0, rt_flags | NOUVEAU_BO_OR, chan->vram->handle, chan->gart->handle); OUT_RING(chan, RING_3D(NV34TCL_COLOR1_OFFSET, 2)); OUT_RELOC(chan, nvfx->hw_rt[1].bo, nvfx->hw_rt[1].offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); OUT_RING(chan, nvfx->hw_rt[1].pitch); } if(nvfx->is_nv4x) { if (rt_enable & NV40TCL_RT_ENABLE_COLOR2) { OUT_RING(chan, RING_3D(NV40TCL_DMA_COLOR2, 1)); OUT_RELOC(chan, nvfx->hw_rt[2].bo, 0, rt_flags | NOUVEAU_BO_OR, chan->vram->handle, chan->gart->handle); OUT_RING(chan, RING_3D(NV40TCL_COLOR2_OFFSET, 1)); OUT_RELOC(chan, nvfx->hw_rt[2].bo, nvfx->hw_rt[2].offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); OUT_RING(chan, RING_3D(NV40TCL_COLOR2_PITCH, 1)); OUT_RING(chan, nvfx->hw_rt[2].pitch); } if (rt_enable & NV40TCL_RT_ENABLE_COLOR3) { OUT_RING(chan, RING_3D(NV40TCL_DMA_COLOR3, 1)); OUT_RELOC(chan, nvfx->hw_rt[3].bo, 0, rt_flags | NOUVEAU_BO_OR, chan->vram->handle, chan->gart->handle); OUT_RING(chan, RING_3D(NV40TCL_COLOR3_OFFSET, 1)); OUT_RELOC(chan, nvfx->hw_rt[3].bo, nvfx->hw_rt[3].offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); OUT_RING(chan, RING_3D(NV40TCL_COLOR3_PITCH, 1)); OUT_RING(chan, nvfx->hw_rt[3].pitch); } } if (zeta_format) { OUT_RING(chan, RING_3D(NV34TCL_DMA_ZETA, 1)); OUT_RELOC(chan, nvfx->hw_zeta.bo, 0, rt_flags | NOUVEAU_BO_OR, chan->vram->handle, chan->gart->handle); OUT_RING(chan, RING_3D(NV34TCL_ZETA_OFFSET, 1)); /* TODO: reverse engineer LMA */ OUT_RELOC(chan, nvfx->hw_zeta.bo, nvfx->hw_zeta.offset, rt_flags | NOUVEAU_BO_LOW, 0, 0); if(nvfx->is_nv4x) { OUT_RING(chan, RING_3D(NV40TCL_ZETA_PITCH, 1)); OUT_RING(chan, nvfx->hw_zeta.pitch); } } OUT_RING(chan, RING_3D(NV34TCL_RT_ENABLE, 1)); OUT_RING(chan, rt_enable); OUT_RING(chan, RING_3D(NV34TCL_RT_HORIZ, 3)); OUT_RING(chan, (w << 16) | 0); OUT_RING(chan, (h << 16) | 0); OUT_RING(chan, rt_format); OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_HORIZ, 2)); OUT_RING(chan, (w << 16) | 0); OUT_RING(chan, (h << 16) | 0); OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_CLIP_HORIZ(0), 2)); OUT_RING(chan, ((w - 1) << 16) | 0); OUT_RING(chan, ((h - 1) << 16) | 0); OUT_RING(chan, RING_3D(0x1d88, 1)); OUT_RING(chan, (1 << 12) | h); if(!nvfx->is_nv4x) { /* Wonder why this is needed, context should all be set to zero on init */ /* TODO: we can most likely remove this, after putting it in context init */ OUT_RING(chan, RING_3D(NV34TCL_VIEWPORT_TX_ORIGIN, 1)); OUT_RING(chan, 0); } } void nvfx_framebuffer_relocate(struct nvfx_context *nvfx) { struct nouveau_channel *chan = nvfx->screen->base.channel; unsigned rt_flags = NOUVEAU_BO_RDWR | NOUVEAU_BO_VRAM; rt_flags |= NOUVEAU_BO_DUMMY; MARK_RING(chan, 20, 20); #define DO_(var, pfx, name) \ if(var.bo) { \ OUT_RELOC(chan, var.bo, RING_3D(pfx##TCL_DMA_##name, 1), rt_flags, 0, 0); \ OUT_RELOC(chan, var.bo, 0, \ rt_flags | NOUVEAU_BO_OR, \ chan->vram->handle, chan->gart->handle); \ OUT_RELOC(chan, var.bo, RING_3D(pfx##TCL_##name##_OFFSET, 1), rt_flags, 0, 0); \ OUT_RELOC(chan, var.bo, \ var.offset, rt_flags | NOUVEAU_BO_LOW, \ 0, 0); \ } #define DO(pfx, num) DO_(nvfx->hw_rt[num], pfx, COLOR##num) DO(NV34, 0); DO(NV34, 1); DO(NV40, 2); DO(NV40, 3); DO_(nvfx->hw_zeta, NV34, ZETA); }