diff options
Diffstat (limited to 'src/gallium/drivers/nvfx/nvfx_state_fb.c')
-rw-r--r-- | src/gallium/drivers/nvfx/nvfx_state_fb.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/src/gallium/drivers/nvfx/nvfx_state_fb.c b/src/gallium/drivers/nvfx/nvfx_state_fb.c new file mode 100644 index 00000000000..360e569f77c --- /dev/null +++ b/src/gallium/drivers/nvfx/nvfx_state_fb.c @@ -0,0 +1,250 @@ +#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); +} |