/*
* 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;
}