| /* |
| * Copyright 2012 Red Hat Inc. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the "Software"), |
| * to deal in the Software without restriction, including without limitation |
| * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| * and/or sell copies of the Software, and to permit persons to whom the |
| * Software is furnished to do so, subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be included in |
| * all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF |
| * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| * SOFTWARE. |
| * |
| * Authors: Ben Skeggs |
| * |
| */ |
| |
| #include "pipe/p_defines.h" |
| #include "util/u_pack_color.h" |
| |
| #include "nouveau/nouveau_gldefs.h" |
| #include "nouveau/nv_object.xml.h" |
| #include "nv30-40_3d.xml.h" |
| #include "nv30_context.h" |
| #include "nv30_format.h" |
| |
| static INLINE uint32_t |
| pack_rgba(enum pipe_format format, const float *rgba) |
| { |
| union util_color uc; |
| util_pack_color(rgba, format, &uc); |
| return uc.ui; |
| } |
| |
| static INLINE uint32_t |
| pack_zeta(enum pipe_format format, double depth, unsigned stencil) |
| { |
| uint32_t zuint = (uint32_t)(depth * 4294967295.0); |
| if (format != PIPE_FORMAT_Z16_UNORM) |
| return (zuint & 0xffffff00) | (stencil & 0xff); |
| return zuint >> 16; |
| } |
| |
| static void |
| nv30_clear(struct pipe_context *pipe, unsigned buffers, |
| const union pipe_color_union *color, double depth, unsigned stencil) |
| { |
| struct nv30_context *nv30 = nv30_context(pipe); |
| struct nouveau_pushbuf *push = nv30->base.pushbuf; |
| struct pipe_framebuffer_state *fb = &nv30->framebuffer; |
| uint32_t colr = 0, zeta = 0, mode = 0; |
| |
| if (!nv30_state_validate(nv30, TRUE)) |
| return; |
| |
| if (buffers & PIPE_CLEAR_COLOR && fb->nr_cbufs) { |
| colr = pack_rgba(fb->cbufs[0]->format, color->f); |
| mode |= NV30_3D_CLEAR_BUFFERS_COLOR_R | |
| NV30_3D_CLEAR_BUFFERS_COLOR_G | |
| NV30_3D_CLEAR_BUFFERS_COLOR_B | |
| NV30_3D_CLEAR_BUFFERS_COLOR_A; |
| } |
| |
| if (fb->zsbuf) { |
| zeta = pack_zeta(fb->zsbuf->format, depth, stencil); |
| if (buffers & PIPE_CLEAR_DEPTH) |
| mode |= NV30_3D_CLEAR_BUFFERS_DEPTH; |
| if (buffers & PIPE_CLEAR_STENCIL) |
| mode |= NV30_3D_CLEAR_BUFFERS_STENCIL; |
| } |
| |
| /*XXX: wtf? fixes clears sometimes not clearing on nv3x... */ |
| if (nv30->screen->eng3d->oclass < NV40_3D_CLASS) { |
| BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3); |
| PUSH_DATA (push, zeta); |
| PUSH_DATA (push, colr); |
| PUSH_DATA (push, mode); |
| } |
| |
| BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 3); |
| PUSH_DATA (push, zeta); |
| PUSH_DATA (push, colr); |
| PUSH_DATA (push, mode); |
| |
| nv30_state_release(nv30); |
| } |
| |
| static void |
| nv30_clear_render_target(struct pipe_context *pipe, struct pipe_surface *ps, |
| const union pipe_color_union *color, |
| unsigned x, unsigned y, unsigned w, unsigned h) |
| { |
| struct nv30_context *nv30 = nv30_context(pipe); |
| struct nv30_surface *sf = nv30_surface(ps); |
| struct nv30_miptree *mt = nv30_miptree(ps->texture); |
| struct nouveau_pushbuf *push = nv30->base.pushbuf; |
| struct nouveau_object *eng3d = nv30->screen->eng3d; |
| struct nouveau_pushbuf_refn refn; |
| uint32_t rt_format; |
| |
| rt_format = nv30_format(pipe->screen, ps->format)->hw; |
| if (util_format_get_blocksize(ps->format) == 4) |
| rt_format |= NV30_3D_RT_FORMAT_ZETA_Z24S8; |
| else |
| rt_format |= NV30_3D_RT_FORMAT_ZETA_Z16; |
| |
| if (nv30_miptree(ps->texture)->swizzled) { |
| rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED; |
| rt_format |= util_logbase2(sf->width) << 16; |
| rt_format |= util_logbase2(sf->height) << 24; |
| } else { |
| rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR; |
| } |
| |
| refn.bo = mt->base.bo; |
| refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR; |
| if (nouveau_pushbuf_space(push, 16, 1, 0) || |
| nouveau_pushbuf_refn (push, &refn, 1)) |
| return; |
| |
| BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1); |
| PUSH_DATA (push, NV30_3D_RT_ENABLE_COLOR0); |
| BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3); |
| PUSH_DATA (push, sf->width << 16); |
| PUSH_DATA (push, sf->height << 16); |
| PUSH_DATA (push, rt_format); |
| BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 2); |
| if (eng3d->oclass < NV40_3D_CLASS) |
| PUSH_DATA (push, (sf->pitch << 16) | sf->pitch); |
| else |
| PUSH_DATA (push, sf->pitch); |
| PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0); |
| BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2); |
| PUSH_DATA (push, (w << 16) | x); |
| PUSH_DATA (push, (h << 16) | y); |
| |
| BEGIN_NV04(push, NV30_3D(CLEAR_COLOR_VALUE), 2); |
| PUSH_DATA (push, pack_rgba(ps->format, color->f)); |
| PUSH_DATA (push, NV30_3D_CLEAR_BUFFERS_COLOR_R | |
| NV30_3D_CLEAR_BUFFERS_COLOR_G | |
| NV30_3D_CLEAR_BUFFERS_COLOR_B | |
| NV30_3D_CLEAR_BUFFERS_COLOR_A); |
| |
| nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR; |
| } |
| |
| static void |
| nv30_clear_depth_stencil(struct pipe_context *pipe, struct pipe_surface *ps, |
| unsigned buffers, double depth, unsigned stencil, |
| unsigned x, unsigned y, unsigned w, unsigned h) |
| { |
| struct nv30_context *nv30 = nv30_context(pipe); |
| struct nv30_surface *sf = nv30_surface(ps); |
| struct nv30_miptree *mt = nv30_miptree(ps->texture); |
| struct nouveau_pushbuf *push = nv30->base.pushbuf; |
| struct nouveau_object *eng3d = nv30->screen->eng3d; |
| struct nouveau_pushbuf_refn refn; |
| uint32_t rt_format, mode = 0; |
| |
| rt_format = nv30_format(pipe->screen, ps->format)->hw; |
| if (util_format_get_blocksize(ps->format) == 4) |
| rt_format |= NV30_3D_RT_FORMAT_COLOR_A8R8G8B8; |
| else |
| rt_format |= NV30_3D_RT_FORMAT_COLOR_R5G6B5; |
| |
| if (nv30_miptree(ps->texture)->swizzled) { |
| rt_format |= NV30_3D_RT_FORMAT_TYPE_SWIZZLED; |
| rt_format |= util_logbase2(sf->width) << 16; |
| rt_format |= util_logbase2(sf->height) << 24; |
| } else { |
| rt_format |= NV30_3D_RT_FORMAT_TYPE_LINEAR; |
| } |
| |
| if (buffers & PIPE_CLEAR_DEPTH) |
| mode |= NV30_3D_CLEAR_BUFFERS_DEPTH; |
| if (buffers & PIPE_CLEAR_STENCIL) |
| mode |= NV30_3D_CLEAR_BUFFERS_STENCIL; |
| |
| refn.bo = mt->base.bo; |
| refn.flags = NOUVEAU_BO_VRAM | NOUVEAU_BO_WR; |
| if (nouveau_pushbuf_space(push, 32, 1, 0) || |
| nouveau_pushbuf_refn (push, &refn, 1)) |
| return; |
| |
| BEGIN_NV04(push, NV30_3D(RT_ENABLE), 1); |
| PUSH_DATA (push, 0); |
| BEGIN_NV04(push, NV30_3D(RT_HORIZ), 3); |
| PUSH_DATA (push, sf->width << 16); |
| PUSH_DATA (push, sf->height << 16); |
| PUSH_DATA (push, rt_format); |
| if (eng3d->oclass < NV40_3D_CLASS) { |
| BEGIN_NV04(push, NV30_3D(COLOR0_PITCH), 1); |
| PUSH_DATA (push, (sf->pitch << 16) | sf->pitch); |
| } else { |
| BEGIN_NV04(push, NV40_3D(ZETA_PITCH), 1); |
| PUSH_DATA (push, sf->pitch); |
| } |
| BEGIN_NV04(push, NV30_3D(ZETA_OFFSET), 1); |
| PUSH_RELOC(push, mt->base.bo, sf->offset, NOUVEAU_BO_LOW, 0, 0); |
| BEGIN_NV04(push, NV30_3D(SCISSOR_HORIZ), 2); |
| PUSH_DATA (push, (w << 16) | x); |
| PUSH_DATA (push, (h << 16) | y); |
| |
| BEGIN_NV04(push, NV30_3D(CLEAR_DEPTH_VALUE), 1); |
| PUSH_DATA (push, pack_zeta(ps->format, depth, stencil)); |
| BEGIN_NV04(push, NV30_3D(CLEAR_BUFFERS), 1); |
| PUSH_DATA (push, mode); |
| |
| nv30->dirty |= NV30_NEW_FRAMEBUFFER | NV30_NEW_SCISSOR; |
| } |
| |
| void |
| nv30_clear_init(struct pipe_context *pipe) |
| { |
| pipe->clear = nv30_clear; |
| pipe->clear_render_target = nv30_clear_render_target; |
| pipe->clear_depth_stencil = nv30_clear_depth_stencil; |
| } |