summaryrefslogtreecommitdiffstats
path: root/src/gallium/drivers/nvfx/nv04_2d.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gallium/drivers/nvfx/nv04_2d.c')
-rw-r--r--src/gallium/drivers/nvfx/nv04_2d.c1393
1 files changed, 0 insertions, 1393 deletions
diff --git a/src/gallium/drivers/nvfx/nv04_2d.c b/src/gallium/drivers/nvfx/nv04_2d.c
deleted file mode 100644
index e2fadd33e1c..00000000000
--- a/src/gallium/drivers/nvfx/nv04_2d.c
+++ /dev/null
@@ -1,1393 +0,0 @@
-/**************************************************************************
- *
- * Copyright 2009 Ben Skeggs
- * Copyright 2009 Younes Manton
- * Copyright 2010 Luca Barbieri
- * All Rights Reserved.
- *
- * 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, sub license, 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 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
- * NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
- * AND/OR ITS SUPPLIERS 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.
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- **************************************************************************/
-
-/* this code has no Mesa or Gallium dependency and can be reused in the classic Mesa driver or DDX */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <nouveau/nouveau_device.h>
-#include <nouveau/nouveau_channel.h>
-#include <nouveau/nouveau_bo.h>
-#include <nouveau/nouveau_notifier.h>
-#include <nouveau/nouveau_grobj.h>
-#include <nouveau/nv04_pushbuf.h>
-#include "nv04_2d.h"
-
-#include "nouveau/nv_object.xml.h"
-#include "nouveau/nv_m2mf.xml.h"
-#include "nv01_2d.xml.h"
-
-/* avoid depending on Mesa/Gallium */
-#ifdef __GNUC__
-#define likely(x) __builtin_expect(!!(x), 1)
-#define unlikely(x) __builtin_expect(!!(x), 0)
-#else
-#define likely(x) !!(x)
-#define unlikely(x) !!(x)
-#endif
-
-#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) )
-#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) )
-
-struct nv04_2d_context
-{
- struct nouveau_notifier *ntfy;
- struct nouveau_grobj *surf2d;
- struct nouveau_grobj *swzsurf;
- struct nouveau_grobj *m2mf;
- struct nouveau_grobj *rect;
- struct nouveau_grobj *sifm;
- struct nouveau_grobj *blit;
-};
-
-static inline int
-align(int value, int alignment)
-{
- return (value + alignment - 1) & ~(alignment - 1);
-}
-
-static inline int
-util_is_pot(unsigned x)
-{
- return (x & (x - 1)) == 0;
-}
-
-/* Integer base-2 logarithm, rounded towards zero. */
-static inline unsigned log2i(unsigned i)
-{
- unsigned r = 0;
-
- if (i & 0xffff0000) {
- i >>= 16;
- r += 16;
- }
- if (i & 0x0000ff00) {
- i >>= 8;
- r += 8;
- }
- if (i & 0x000000f0) {
- i >>= 4;
- r += 4;
- }
- if (i & 0x0000000c) {
- i >>= 2;
- r += 2;
- }
- if (i & 0x00000002) {
- r += 1;
- }
- return r;
-}
-
-//#define NV04_REGION_DEBUG
-
-// Yes, we really want to inline everything, since all the functions are used only once
-#if defined(__GNUC__) && !defined(DEBUG)
-#define inline __attribute__((always_inline)) inline
-#endif
-
-static inline unsigned
-nv04_swizzle_bits_square(unsigned x, unsigned y)
-{
- unsigned u = (x & 0x001) << 0 |
- (x & 0x002) << 1 |
- (x & 0x004) << 2 |
- (x & 0x008) << 3 |
- (x & 0x010) << 4 |
- (x & 0x020) << 5 |
- (x & 0x040) << 6 |
- (x & 0x080) << 7 |
- (x & 0x100) << 8 |
- (x & 0x200) << 9 |
- (x & 0x400) << 10 |
- (x & 0x800) << 11;
-
- unsigned v = (y & 0x001) << 1 |
- (y & 0x002) << 2 |
- (y & 0x004) << 3 |
- (y & 0x008) << 4 |
- (y & 0x010) << 5 |
- (y & 0x020) << 6 |
- (y & 0x040) << 7 |
- (y & 0x080) << 8 |
- (y & 0x100) << 9 |
- (y & 0x200) << 10 |
- (y & 0x400) << 11 |
- (y & 0x800) << 12;
- return v | u;
-}
-
-/* rectangular swizzled textures are linear concatenations of swizzled square tiles */
-static inline unsigned
-nv04_swizzle_bits_2d(unsigned x, unsigned y, unsigned w, unsigned h)
-{
- if(h <= 1)
- return x;
- else
- {
- unsigned s = MIN2(w, h);
- unsigned m = s - 1;
- return (((x | y) & ~m) * s) | nv04_swizzle_bits_square(x & m, y & m);
- }
-}
-
-// general 3D texture case
-static inline unsigned
-nv04_swizzle_bits(unsigned x, unsigned y, unsigned z, unsigned w, unsigned h, unsigned d)
-{
- if(d <= 1)
- return nv04_swizzle_bits_2d(x, y, w, h);
- else
- {
- // TODO: autogenerate code for all possible texture sizes (13 * 13 * 13 with dims <= 4096) and do a single indirect call
- unsigned v = 0;
- w >>= 1;
- h >>= 1;
- d >>= 1;
- for(int i = 0;;)
- {
- int oldi = i;
- if(likely(w))
- {
- v |= (x & 1) << i;
- x >>= 1;
- w >>= 1;
- ++i;
- }
-
- if(likely(h))
- {
- v |= (y & 1) << i;
- y >>= 1;
- h >>= 1;
- ++i;
- }
-
- if(likely(d))
- {
- v |= (z & 1) << i;
- z >>= 1;
- d >>= 1;
- ++i;
- }
-
- if(i == oldi)
- break;
- }
- return v;
- }
-}
-
-unsigned
-nv04_region_begin(struct nv04_region* rgn, unsigned w, unsigned h)
-{
- if(rgn->pitch)
- return rgn->pitch * rgn->y + (rgn->x << rgn->bpps);
- else
- return nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d) << rgn->bpps;
-}
-
-unsigned
-nv04_region_end(struct nv04_region* rgn, unsigned w, unsigned h)
-{
- if(rgn->pitch)
- return rgn->pitch * (rgn->y + h - 1) + ((rgn->x + w) << rgn->bpps);
- else
- return (nv04_swizzle_bits(rgn->x + w - 1, rgn->y + h - 1, rgn->z, rgn->w, rgn->h, rgn->d) + 1) << rgn->bpps;
-}
-
-// *pitch = -1 -> use 3D swizzling for (x, y), *pitch = 0 -> use 2D swizzling, other *pitch -> use linear calculations
-// returns 2 if pixel order is 3D-swizzled and 1 if subrect is 2D-swizzled
-/* *pitch == -1 ret = 0 -> 3D swizzled subrect
- * *pitch == 0 ret = 0 -> 2D swizzled subrect
- * *pitch > 0 ret = 0 -> linear subrect
- * *pitch > 0 ret = 1 -> linear subrect, but with swizzled 3D data inside
- */
-
-static inline void
-nv04_region_print(struct nv04_region* rgn)
-{
- fprintf(stderr, "<%i[%i]> ", rgn->bo->handle, rgn->offset);
- if(rgn->pitch)
- fprintf(stderr, "lin %i", rgn->pitch);
- else
- fprintf(stderr, "swz %ix%ix%i", rgn->w, rgn->h, rgn->d);
- fprintf(stderr, " (%i, %i, %i)", rgn->x, rgn->y, rgn->z);
-}
-
-static inline void
-nv04_region_assert(struct nv04_region* rgn, unsigned w, unsigned h)
-{
- unsigned end = rgn->offset + nv04_region_end(rgn, w, h);
-
- assert(rgn->offset <= (int)rgn->bo->size);
- assert(end <= rgn->bo->size);
- (void) end;
- if(!rgn->pitch) {
- assert(util_is_pot(rgn->w));
- assert(util_is_pot(rgn->h));
- }
-}
-
-/* determine if region can be linearized or fake-linearized */
-static inline int
-nv04_region_is_contiguous(struct nv04_region* rgn, int w, int h)
-{
- int surf_min;
- int rect_min;
-
- if(rgn->pitch)
- return rgn->pitch == w << rgn->bpps;
-
- // redundant, but this is the fast path for the common case
- if(w == rgn->w && h == rgn->h && rgn->d <= 1)
- return 1;
-
- // must be POT
- if((w & (w - 1)) || (h & (h - 1)))
- return 0;
-
- // must be aligned
- if((rgn->x & (w - 1)) || (rgn->y & (h - 1)))
- return 0;
-
- if(rgn->d > 1)
- return 0;
-
- surf_min = MIN2(rgn->w, rgn->h);
- rect_min = MIN2(w, h);
-
- if((rect_min == surf_min) || (w == h) || (w == 2 * h))
- return 1;
-
- return 0;
-}
-
-// double the pitch until it is larger than the alignment, or the height becomes odd or 1
-static inline void
-nv04_region_contiguous_shape(struct nv04_region* rgn, int* w, int* h, int align)
-{
- while(!(*h & 1) && (*w << rgn->bpps) < (1 << align))
- {
- *w <<= 1;
- *h >>= 1;
- }
-
- while((*w << rgn->bpps) > 16384 && !(*w & 1))
- {
- *w >>= 1;
- *h <<= 1;
- }
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tCONTIGUOUS %ix%i\n", *w, *h);
-#endif
-}
-
-static inline void
-nv04_region_linearize_contiguous(struct nv04_region* rgn, unsigned w, unsigned h)
-{
- int pos;
- if(rgn->pitch)
- {
- rgn->offset += rgn->y * rgn->pitch + (rgn->x << rgn->bpps);
- rgn->x = 0;
- rgn->y = 0;
- }
- else
- {
- rgn->offset += (rgn->w * rgn->h * rgn->z) << rgn->bpps;
- pos = nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d);
- rgn->x = pos & (w - 1);
- rgn->y = pos / w;
- }
- rgn->pitch = w << rgn->bpps;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tLINEARIZE ");
- nv04_region_print(rgn);
- fprintf(stderr, "\n");
-#endif
-}
-
- /* preserve the offset! */
- /*
- rgn->pitch = util_format_get_stride(rgn->format, w);
- int pos = nv04_swizzle_bits(rgn->x, rgn->y, rgn->z, rgn->w, rgn->h, rgn->d);
- rgn->x = pos & (w - 1);
- rgn->y = pos & ~(w - 1);
- */
-
- /*
- rgn->offset +=
- rgn->pitch = util_format_get_stride(rgn->format, w);
- rgn->x = 0;
- rgn->y = 0;
- */
-
-/* This code will get used for, and always succeed on:
- * - 4x2 1bpp swizzled texture mipmap levels
- * - linear regions created by linearization
- *
- * This code will get used for, and MAY work for:
- * - misaligned texture blanket
- * - linear surfaces created without wide_pitch (in this case, it will only work if we are lucky)
- *
- * The general case requires splitting the region in 2.
- */
-static inline int
-nv04_region_do_align_offset(struct nv04_region* rgn, unsigned w, unsigned h, int shift)
-{
- if(rgn->pitch > 0)
- {
- assert(!(rgn->offset & ((1 << rgn->bpps) - 1))); // fatal!
-
- if(h <= 1)
- {
- int delta;
- rgn->offset += rgn->y * rgn->pitch + (rgn->x << rgn->bpps);
- delta = rgn->offset & ((1 << shift) - 1);
- rgn->y = 0;
- rgn->x = delta >> rgn->bpps;
- rgn->offset -= delta;
- rgn->pitch = align((rgn->x + w) << rgn->bpps, 1 << shift);
- }
- else
- {
- int delta = rgn->offset & ((1 << shift) - 1);
- int newxo = (rgn->x << rgn->bpps) + delta;
- int dy = newxo / rgn->pitch;
- newxo -= dy * rgn->pitch;
- if((newxo + (w << rgn->bpps)) > rgn->pitch)
- {
- // TODO: split the region into two rectangles (!) if *really* necessary, unless the hardware actually supports "wrapping" rectangles
- // this does not happen if the surface is pitch-aligned, which it should always be
- assert(0);
- return -1;
- }
- rgn->x = newxo >> rgn->bpps;
- rgn->y += dy;
- }
- }
- else
- {
- int size;
- int min;
- int v;
-
- // we don't care about the alignment of 3D surfaces since the 2D engine can't use them
- if(rgn->d < 0)
- return -1;
-
- min = MIN2(rgn->w, rgn->h);
- size = min * min << rgn->bpps;
-
- // this is unfixable, and should not be happening
- if(rgn->offset & (size - 1))
- return -1;
-
- v = (rgn->offset & ((1 << shift) - 1)) / size;
- rgn->offset -= v * size;
-
- if(rgn->h == min)
- {
- unsigned w;
- rgn->x += rgn->h * v;
- w = rgn->w + rgn->h * v;
-
- while(rgn->w < w)
- rgn->w += rgn->w;
- }
- else
- {
- unsigned h;
- rgn->y += rgn->w * v;
- h = rgn->h + rgn->w * v;
-
- while(rgn->h < h)
- rgn->h += rgn->h;
- }
- }
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tALIGNED ");
- nv04_region_print(rgn);
- fprintf(stderr, "\n");
-#endif
- return 0;
-}
-
-// both pitch and shift
-// will leave the region unchanged if it fails
-static inline int
-nv04_region_align(struct nv04_region* rgn, unsigned w, unsigned h, int shift)
-{
- if(rgn->pitch & ((1 << shift) - 1))
- {
- if(h == 1)
- goto do_align; /* this will fix pitch too in this case */
- else
- return -1;
- }
-
- if(rgn->offset & ((1 << shift) - 1))
- {
- do_align:
- if(nv04_region_do_align_offset(rgn, w, h, shift))
- return -1;
- }
- return 0;
-}
-
-/* this contains 22 different copy loops after preprocessing. unfortunately, it's necessary */
-void
-nv04_region_copy_cpu(struct nv04_region* dst, struct nv04_region* src, int w, int h)
-{
- uint8_t* mdst;
- uint8_t* msrc;
- int size;
-
- if(dst->bo != src->bo)
- {
- nouveau_bo_map(dst->bo, NOUVEAU_BO_WR);
- nouveau_bo_map(src->bo, NOUVEAU_BO_RD);
- }
- else
- nouveau_bo_map(dst->bo, NOUVEAU_BO_WR | NOUVEAU_BO_RD);
-
- mdst = (uint8_t*)dst->bo->map + dst->offset;
- msrc = (uint8_t*)src->bo->map + src->offset;
-
- size = w << dst->bpps;
-
- nv04_region_assert(dst, w, h);
- nv04_region_assert(src, w, h);
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tRGN_COPY_CPU [%i, %i: %i] ", w, h, dst->bpps);
- for(int i = 0; i < 2; ++i)
- {
- nv04_region_print(i ? src : dst);
- fprintf(stderr, i ? "\n" : " <- ");
- }
-
-// for(int i = 0; i < 16; ++i)
-// fprintf(stderr, "%02x ", msrc[i]);
-// fprintf(stderr, "\n");
-#endif
-
- // TODO: support overlapping copies!
- if(src->pitch && dst->pitch)
- {
- mdst += dst->y * dst->pitch + (dst->x << dst->bpps);
- msrc += src->y * src->pitch + (src->x << src->bpps);
- if(dst->bo != src->bo)
- goto simple;
- else if(mdst < msrc)
- {
- if(mdst + size <= msrc)
- {
-simple:
- for(int iy = 0; iy < h; ++iy)
- {
- assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size);
- assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size);
- memcpy(mdst, msrc, size);
- msrc += src->pitch; mdst += dst->pitch;
- }
- }
- else
- {
- for(int iy = 0; iy < h; ++iy)
- {
- assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size);
- assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size);
- memmove(mdst, msrc, size);
- msrc += src->pitch; mdst += dst->pitch;
- }
- }
- }
- else
- {
- /* copy backwards so we don't destroy data we have to read yet */
- if(msrc + size <= mdst)
- {
- for(int iy = h - 1; iy >= 0; --iy)
- {
- assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size);
- assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size);
- memcpy(mdst, msrc, size);
- msrc += src->pitch; mdst += dst->pitch;
- }
- }
- else
- {
- for(int iy = h - 1; iy >= 0; --iy)
- {
- assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size);
- assert(msrc + size <= (uint8_t*)src->bo->map + src->bo->size);
- memmove(mdst, msrc, size);
- msrc += src->pitch; mdst += dst->pitch;
- }
- }
- }
- }
- else
- {
- int* dswx = NULL;
- int* dswy = NULL;
- int* sswx = NULL;
- int* sswy = NULL;
- int dir;
-
- if(!dst->pitch)
- {
- dswx = alloca(w * sizeof(int));
- for(int ix = 0; ix < w; ++ix) // we are adding, so z cannot be contributed by both
- dswx[ix] = nv04_swizzle_bits(dst->x + ix, 0, 0, dst->w, dst->h, dst->d);
- dswy = alloca(h * sizeof(int));
- for(int iy = 0; iy < h; ++iy)
- dswy[iy] = nv04_swizzle_bits(0, dst->y + iy, dst->z, dst->w, dst->h, dst->d);
- }
-
- if(!src->pitch)
- {
- sswx = alloca(w * sizeof(int));
- for(int ix = 0; ix < w; ++ix)
- sswx[ix] = nv04_swizzle_bits(src->x + ix, 0, 0, src->w, src->h, src->d);
- sswy = alloca(h * sizeof(int));
- for(int iy = 0; iy < h; ++iy)
- sswy[iy] = nv04_swizzle_bits(0, src->y + iy, src->z, src->w, src->h, src->d);
- }
-
- dir = 1;
- /* do backwards copies for overlapping swizzled surfaces */
- if(dst->pitch == src->pitch && dst->offset == src->offset)
- {
- if(dst->y > src->y || (dst->y == src->y && dst->x > src->x))
- dir = -1;
- }
-
-#define SWIZZLED_COPY_LOOPS
- if(dir == 1)
- {
- int dir = 1;
-#define LOOP_Y for(int iy = 0; iy < h; ++iy)
-#define LOOP_X for(int ix = 0; ix < w; ++ix)
-#include "nv04_2d_loops.h"
-#undef LOOP_X
-#undef LOOP_Y
- }
- else
- {
- int dir = -1;
-#define LOOP_Y for(int iy = h - 1; iy >= 0; --iy)
-#define LOOP_X for(int ix = w - 1; ix >= 0; --ix)
-#include "nv04_2d_loops.h"
-#undef LOOP_X
-#undef LOOP_Y
- }
-#undef SWIZZLED_COPY_LOOP
- }
-
- if(src->bo != dst->bo)
- nouveau_bo_unmap(src->bo);
- nouveau_bo_unmap(dst->bo);
-}
-
-/* TODO: if the destination is swizzled, we are doing random writes, which causes write combining to fail
- * the alternative is to read, modify and copy back, which may or may not be faster
- * loading 3D textures is a common case that hits this and could probably benefit from the temporary
- */
-void
-nv04_region_fill_cpu(struct nv04_region* dst, int w, int h, unsigned value)
-{
- uint8_t* mdst = (nouveau_bo_map(dst->bo, NOUVEAU_BO_WR), (uint8_t*)dst->bo->map + dst->offset);
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tRGN_FILL_CPU ");
- nv04_region_print(dst);
- fprintf(stderr, "\n");
-#endif
-
- nv04_region_assert(dst, w, h);
-
- if(dst->pitch)
- {
- unsigned size = w << dst->bpps;
-
-#define FILL(T) do { \
- for(int iy = 0; iy < h; ++iy) \
- { \
- assert((char*)((T*)mdst + w) <= (char*)dst->bo->map + dst->bo->size); \
- for(int ix = 0; ix < w; ++ix) \
- ((T*)mdst)[ix] = (T)value; \
- mdst += dst->pitch; \
- } \
- } while(0)
-
- mdst += dst->y * dst->pitch + (dst->x << dst->bpps);
-
- if(dst->bpps == 0)
- {
-ms:
- assert(mdst + size * h <= (uint8_t*)dst->bo->map + dst->bo->size);
- if(size == dst->pitch)
- memset(mdst, (uint8_t)value, size * h);
- else
- {
- for(int iy = 0; iy < h; ++iy)
- {
- assert(mdst + size <= (uint8_t*)dst->bo->map + dst->bo->size);
- memset(mdst, (uint8_t)value, size);
- mdst += dst->pitch;
- }
- }
- }
- else if(dst->bpps == 1)
- {
- if(!((uint8_t)value ^ (uint8_t)(value >> 8)))
- goto ms;
-
- FILL(uint16_t);
- }
- else if(dst->bpps == 2)
- {
- if(value == (uint8_t)value * 0x1010101)
- goto ms;
- FILL(uint32_t);
- }
- else
- assert(0);
-#undef FILL
- }
- else
- {
- int* dswx;
- int* dswy;
-
- dswx = alloca(w * sizeof(int));
- for(int ix = 0; ix < w; ++ix)
- dswx[ix] = nv04_swizzle_bits(dst->x + ix, 0, dst->z, dst->w, dst->h, dst->d);
- dswy = alloca(h * sizeof(int));
- for(int iy = 0; iy < h; ++iy)
- dswy[iy] = nv04_swizzle_bits(0, dst->y + iy, dst->z, dst->w, dst->h, dst->d);
-
-#define FILL(T) do { \
- T tvalue = (T)value; \
- for(int iy = 0; iy < h; ++iy) \
- { \
- T* pdst = (T*)mdst + dswy[iy]; \
- for(int ix = 0; ix < w; ++ix) \
- { \
- assert((uint8_t*)&pdst[dswx[ix] + 1] <= (uint8_t*)dst->bo->map + dst->bo->size); \
- pdst[dswx[ix]] = tvalue; \
- } \
- } \
- } while(0)
-
- if(dst->bpps == 0)
- FILL(uint8_t);
- else if(dst->bpps == 1)
- FILL(uint16_t);
- else if(dst->bpps == 2)
- FILL(uint32_t);
- else
- assert(0 && "unhandled bpp");
-#undef FILL
- }
-
- nouveau_bo_unmap(dst->bo);
-}
-
-static inline int
-nv04_region_cs2d_format(struct nv04_region* rgn)
-{
- switch(rgn->bpps) {
- case 0:
- return NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
- case 1:
- if(rgn->one_bits >= 1)
- return NV04_CONTEXT_SURFACES_2D_FORMAT_X1R5G5B5_X1R5G5B5;
- else
- return NV04_CONTEXT_SURFACES_2D_FORMAT_R5G6B5;
- case 2:
- if(rgn->one_bits >= 8)
- return NV04_CONTEXT_SURFACES_2D_FORMAT_X8R8G8B8_X8R8G8B8;
- else
- return NV04_CONTEXT_SURFACES_2D_FORMAT_A8R8G8B8;
- default:
- return -1;
- }
-}
-
-static inline int
-nv04_region_sifm_format(struct nv04_region* rgn)
-{
- switch(rgn->bpps) {
- case 0:
- return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_Y8;
- case 1:
- if(rgn->one_bits >= 1)
- return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X1R5G5B5;
- else
- return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_R5G6B5;
- case 2:
- if(rgn->one_bits >= 8)
- return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_X8R8G8B8;
- else
- return NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_FORMAT_A8R8G8B8;
- default:
- return -1;
- }
-}
-static void
-nv04_region_copy_swizzle(struct nv04_2d_context *ctx,
- struct nv04_region* dst,
- struct nv04_region* src,
- int w, int h)
-{
- struct nouveau_channel *chan = ctx->swzsurf->channel;
- struct nouveau_grobj *swzsurf = ctx->swzsurf;
- struct nouveau_grobj *sifm = ctx->sifm;
- int cs2d_format = nv04_region_cs2d_format(dst);
- int sifm_format = nv04_region_sifm_format(src);
- /* Max width & height may not be the same on all HW, but must be POT */
- unsigned max_shift = 10;
- unsigned cw = 1 << max_shift;
- unsigned ch = 1 << max_shift;
- unsigned sx = dst->x >> max_shift;
- unsigned sy = dst->y >> max_shift;
- unsigned ex = (dst->x + w - 1) >> max_shift;
- unsigned ey = (dst->y + h - 1) >> max_shift;
- unsigned chunks = (ex - sx + 1) * (ey - sy + 1);
- unsigned chunk_size;
- if(dst->w < cw)
- cw = dst->w;
- if(dst->h < ch)
- ch = dst->h;
- chunk_size = cw * ch << dst->bpps;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tRGN_COPY_SWIZZLE [%i, %i: %i] ", w, h, dst->bpps);
- for(int i = 0; i < 2; ++i)
- {
- nv04_region_print(i ? src : dst);
- fprintf(stderr, i ? "\n" : " <- ");
- }
-#endif
-
- nv04_region_assert(dst, w, h);
- nv04_region_assert(src, w, h);
-
- MARK_RING (chan, 8 + chunks * 17, 2 + chunks * 2);
-
- BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_DMA_IMAGE, 1);
- OUT_RELOCo(chan, dst->bo,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-
- BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_FORMAT, 1);
- OUT_RING (chan, cs2d_format |
- log2i(cw) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_U__SHIFT |
- log2i(ch) << NV04_SWIZZLED_SURFACE_FORMAT_BASE_SIZE_V__SHIFT);
-
- BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_DMA_IMAGE, 1);
- OUT_RELOCo(chan, src->bo,
- NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
- BEGIN_RING(chan, sifm, NV04_SCALED_IMAGE_FROM_MEMORY_SURFACE, 1);
- OUT_RING (chan, swzsurf->handle);
-
- assert(!(dst->offset & 63));
-
- for (int cy = sy; cy <= ey; ++cy) {
- int ry = MAX2(0, (int)(dst->y - ch * cy));
- int rh = MIN2((int)ch, (int)(dst->y - ch * cy + h)) - ry;
- for (int cx = sx; cx <= ex; ++cx) {
- int rx = MAX2(0, (int)(dst->x - cw * cx));
- int rw = MIN2((int)cw, (int)(dst->x - cw * cx + w)) - rx;
- unsigned dst_offset;
- unsigned src_offset;
-
- BEGIN_RING(chan, swzsurf, NV04_SWIZZLED_SURFACE_OFFSET, 1);
-
- dst_offset = dst->offset + (nv04_swizzle_bits_2d(cx * cw, cy * ch, dst->w, dst->h) << dst->bpps);
- assert(dst_offset <= dst->bo->size);
- assert(dst_offset + chunk_size <= dst->bo->size);
- OUT_RELOCl(chan, dst->bo, dst_offset,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-
- BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION, 9);
- OUT_RING (chan, NV03_SCALED_IMAGE_FROM_MEMORY_COLOR_CONVERSION_TRUNCATE);
- OUT_RING (chan, sifm_format);
- OUT_RING (chan, NV03_SCALED_IMAGE_FROM_MEMORY_OPERATION_SRCCOPY);
- OUT_RING (chan, rx | (ry << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_POINT_Y__SHIFT));
- OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_CLIP_SIZE_H__SHIFT | rw);
- OUT_RING (chan, rx | (ry << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_POINT_Y__SHIFT));
- OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_OUT_SIZE_H__SHIFT | rw);
- OUT_RING (chan, 1 << 20);
- OUT_RING (chan, 1 << 20);
-
- BEGIN_RING(chan, sifm, NV03_SCALED_IMAGE_FROM_MEMORY_SIZE, 4);
- OUT_RING (chan, rh << NV03_SCALED_IMAGE_FROM_MEMORY_SIZE_H__SHIFT | align(rw, 8));
- OUT_RING (chan, src->pitch |
- NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_ORIGIN_CENTER |
- NV03_SCALED_IMAGE_FROM_MEMORY_FORMAT_FILTER_POINT_SAMPLE);
- src_offset = src->offset + (cy * ch + ry + src->y - dst->y) * src->pitch + ((cx * cw + rx + src->x - dst->x) << src->bpps);
- assert(src_offset <= src->bo->size);
- assert(src_offset + (src->pitch * (rh - 1)) + (rw << src->bpps) <= src->bo->size);
- OUT_RELOCl(chan, src->bo, src_offset,
- NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
- OUT_RING (chan, 0);
- }
- }
-}
-
-static inline void
-nv04_copy_m2mf_begin(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, struct nouveau_bo* srcbo, unsigned commands)
-{
- struct nouveau_channel *chan = ctx->m2mf->channel;
- struct nouveau_grobj *m2mf = ctx->m2mf;
- MARK_RING (chan, 3 + commands * 9, 2 + commands * 2);
- BEGIN_RING(chan, m2mf, NV04_M2MF_DMA_BUFFER_IN, 2);
- OUT_RELOCo(chan, srcbo,
- NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
- OUT_RELOCo(chan, dstbo,
- NOUVEAU_BO_GART | NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-}
-
-static inline void
-nv04_copy_m2mf_body(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, int* pdstoff, unsigned dstpitch, struct nouveau_bo* srcbo, int* psrcoff, unsigned srcpitch, unsigned size, unsigned lines)
-{
- struct nouveau_channel *chan = ctx->m2mf->channel;
- struct nouveau_grobj *m2mf = ctx->m2mf;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\t\t\tCOPY_M2MF_BODY [%i, %i] <%i[%u]> lin %u <- <%i[%u]> lin %u\n", size, lines, dstbo->handle, *pdstoff, dstpitch, srcbo->handle, *psrcoff, srcpitch);
-#endif
-
- BEGIN_RING(chan, m2mf, NV04_M2MF_OFFSET_IN, 8);
- OUT_RELOCl(chan, srcbo, *psrcoff,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_RD);
- OUT_RELOCl(chan, dstbo, *pdstoff,
- NOUVEAU_BO_VRAM | NOUVEAU_BO_GART | NOUVEAU_BO_WR);
- OUT_RING (chan, srcpitch);
- OUT_RING (chan, dstpitch);
- OUT_RING (chan, size);
- OUT_RING (chan, lines);
- OUT_RING (chan, 0x0101);
- OUT_RING (chan, 0);
-
- *psrcoff += srcpitch * lines;
- *pdstoff += dstpitch * lines;
-}
-
-static void
-nv04_copy_m2mf(struct nv04_2d_context *ctx,
- struct nouveau_bo* dstbo, int dstoff, unsigned dstpitch,
- struct nouveau_bo* srcbo, int srcoff, unsigned srcpitch,
- unsigned size, unsigned h)
-{
- unsigned max_pitch = 32767;
- unsigned max_lines = 2047;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\t\tCOPY_M2MF [%i, %i] <%i[%i]> lin %u <- <%i[%i]> lin %u\n", size, h, dstbo->handle, dstoff, dstpitch, srcbo->handle, srcoff, srcpitch);
-#endif
-
- if(srcpitch <= max_pitch && dstpitch <= max_pitch)
- {
- unsigned full_pages = h / max_lines;
- unsigned leftover_lines = h - full_pages * max_lines;
-
- nv04_copy_m2mf_begin(ctx, dstbo, srcbo, full_pages + !!leftover_lines);
-
- for(unsigned i = 0; i < full_pages; ++i)
- nv04_copy_m2mf_body(ctx, dstbo, &dstoff, dstpitch, srcbo, &srcoff, srcpitch, size, max_lines);
-
- if(leftover_lines)
- nv04_copy_m2mf_body(ctx, dstbo, &dstoff, dstpitch, srcbo, &srcoff, srcpitch, size, leftover_lines);
- }
- else
- {
- unsigned lines = size / max_pitch;
- unsigned leftover = size - lines * max_pitch;
- unsigned full_pages = lines / max_lines;
- unsigned leftover_lines = lines - full_pages * max_lines;
- unsigned srcgap = srcpitch - size;
- unsigned dstgap = dstpitch - size;
-
- nv04_copy_m2mf_begin(ctx, dstbo, srcbo, h * (full_pages + !!leftover_lines + !!leftover));
-
- for(unsigned i = 0; i < h; ++i)
- {
- for(unsigned j = 0; j < full_pages; ++j)
- nv04_copy_m2mf_body(ctx, dstbo, &dstoff, max_pitch, srcbo, &srcoff, max_pitch, max_pitch, max_lines);
-
- if(leftover_lines)
- nv04_copy_m2mf_body(ctx, dstbo, &dstoff, max_pitch, srcbo, &srcoff, max_pitch, max_pitch, leftover_lines);
-
- if(leftover)
- nv04_copy_m2mf_body(ctx, dstbo, &dstoff, leftover, srcbo, &srcoff, leftover, leftover, 1);
-
- srcoff += srcgap;
- dstoff += dstgap;
- }
- }
-}
-
-void
-nv04_memcpy(struct nv04_2d_context *ctx, struct nouveau_bo* dstbo, int dstoff, struct nouveau_bo* srcbo, int srcoff, unsigned size)
-{
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tMEMCPY [%i] <%i[%i]> <- <%i[%i]>\n", size, dstbo->handle, dstoff, srcbo->handle, srcoff);
-#endif
-
- nv04_copy_m2mf(ctx, dstbo, dstoff, size, srcbo, srcoff, size, size, 1);
-}
-
-static void
-nv04_region_copy_m2mf(struct nv04_2d_context *ctx, struct nv04_region *dst, struct nv04_region *src, int w, int h)
-{
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tRGN_COPY_M2MF [%i, %i: %i] ", w, h, dst->bpps);
- for(int i = 0; i < 2; ++i)
- {
- nv04_region_print(i ? src : dst);
- fprintf(stderr, i ? "\n" : " <- ");
- }
-#endif
-
- nv04_region_assert(dst, w, h);
- nv04_region_assert(src, w, h);
- assert(src->pitch);
- assert(dst->pitch);
-
- nv04_copy_m2mf(ctx,
- dst->bo, dst->offset + dst->y * dst->pitch + (dst->x << dst->bpps), dst->pitch,
- src->bo, src->offset + src->y * src->pitch + (src->x << src->bpps), src->pitch,
- w << src->bpps, h);
-}
-
-static inline void
-nv04_region_copy_blit(struct nv04_2d_context *ctx, struct nv04_region* dst, struct nv04_region* src, int w, int h)
-{
- struct nouveau_channel *chan = ctx->surf2d->channel;
- struct nouveau_grobj *surf2d = ctx->surf2d;
- struct nouveau_grobj *blit = ctx->blit;
- int cs2d_format = nv04_region_cs2d_format(dst);
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tRGN_COPY_BLIT [%i, %i: %i] ", w, h, dst->bpps);
- for(int i = 0; i < 2; ++i)
- {
- nv04_region_print(i ? src : dst);
- fprintf(stderr, i ? "\n" : " <- ");
- }
-#endif
-
- assert(!(src->pitch & 63) && src->pitch);
- assert(!(dst->pitch & 63) && dst->pitch);
- nv04_region_assert(dst, w, h);
- nv04_region_assert(src, w, h);
-
- MARK_RING (chan, 12, 4);
- BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
- OUT_RELOCo(chan, src->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
- OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
- BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
- OUT_RING (chan, cs2d_format);
- OUT_RING (chan, (dst->pitch << 16) | src->pitch);
- OUT_RELOCl(chan, src->bo, src->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_RD);
- OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-
- BEGIN_RING(chan, blit, 0x0300, 3);
- OUT_RING (chan, (src->y << 16) | src->x);
- OUT_RING (chan, (dst->y << 16) | dst->x);
- OUT_RING (chan, ( h << 16) | w);
-}
-
-/* THEOREM: a non-linearizable swizzled destination is always 64 byte aligned, except for 4x2 mipmap levels of swizzled 1bpp surfaces
- * HYPOTESIS:
- * 1. The first mipmap level is 64-byte-aligned
- * PROOF:
- * 1. Thus, all mipmaps level with a parent which is 64-byte or more in size are.
- * 2. At 1bpp, the smallest levels with a <= 32-byte parent are either Nx1 or 1xN or size <=8, thus 4x2, 2x2 or 2x4
- * 3. Nx1, 1xN, 2x4, 2x2 have all subrects linearizable. 4x2 does not.
- * 4. At 2/4bpp or more, the smallest levels with a 32-byte parent are 1xN, Nx1 or 2x2
- *
- * However, nv04_region_align handles that.
- */
-
-// 0 -> done, 1 -> do with 3D engine or CPU, -1 -> do with CPU
-// dst and src may be modified, and the possibly modified version should be passed to nv04_region_cpu if necessary
-int
-nv04_region_copy_2d(struct nv04_2d_context *ctx, struct nv04_region* dst, struct nv04_region* src,
- int w, int h, int dst_to_gpu, int src_on_gpu)
-{
- assert(src->bpps == dst->bpps);
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "RGN_COPY [%i, %i: %i] ", w, h, dst->bpps);
- for(int i = 0; i < 2; ++i)
- {
- int gpu = i ? src_on_gpu : dst_to_gpu;
- nv04_region_print(i ? src : dst);
- fprintf(stderr, " %s", gpu ? "gpu" : "cpu");
- fprintf(stderr, i ? "\n" : " <- ");
- }
-#endif
-
- // if they are contiguous and either both swizzled or both linear, reshape
- if(!dst->pitch == !src->pitch
- && nv04_region_is_contiguous(dst, w, h)
- && nv04_region_is_contiguous(src, w, h))
- {
- nv04_region_contiguous_shape(dst, &w, &h, 6);
- nv04_region_linearize_contiguous(dst, w, h);
- nv04_region_linearize_contiguous(src, w, h);
- }
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tOPT ");
- for(int i = 0; i < 2; ++i)
- {
- nv04_region_print(i ? src : dst);
- fprintf(stderr, i ? "\n" : " <- ");
- }
-#endif
-
- /* if the destination is not for GPU _and_ source is on CPU, use CPU */
- /* if the destination is not for GPU _or_ source is on CPU, use CPU only if we think it's faster than the GPU */
- /* TODO: benchmark to find out in which cases exactly we should prefer the CPU */
- if((!dst_to_gpu && !src_on_gpu)
- || (!dst->pitch && dst->d > 1)
- /* 3D swizzled destination are unwritable by the GPU, and 2D swizzled ones are readable only by the 3D engine */
- )
- return -1;
- /* there is no known way to read 2D/3D-swizzled surfaces with the 2D engine
- * ask the caller to use the 3D engine
- * If a format cannot be sampled from the 3D engine there is no point in making it swizzled, so we must not do so
- */
- else if(!src->pitch)
- {
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tCOPY_ENG3D\n");
-#endif
- return 1;
- }
- /* Setup transfer to swizzle the texture to vram if needed */
- else
- {
- if (!dst->pitch)
- {
- if(!dst_to_gpu)
- {
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tCOPY_ENG3D\n");
-#endif
- return 1;
- }
- else
- {
- assert(!nv04_region_align(dst, w, h, 6));
-
- nv04_region_copy_swizzle(ctx, dst, src, w, h);
- return 0;
- }
- }
- else
- {
- /* NV_CONTEXT_SURFACES_2D has buffer alignment restrictions, fallback
- * to NV_M2MF in this case.
- * TODO: is this also true for the source? possibly not
- * TODO: should we just always use m2mf?
- * TODO: if not, add support for multiple operations to copy_blit
- */
-
- if (!dst_to_gpu
- || w > 2047
- || h > 2047
- || (w & 1)
- || nv04_region_align(src, w, h, 6)
- || nv04_region_align(dst, w, h, 6)
- )
- nv04_region_copy_m2mf(ctx, dst, src, w, h);
- else
- nv04_region_copy_blit(ctx, dst, src, w, h);
-
- return 0;
- }
- }
-}
-
-static inline void
-nv04_region_fill_gdirect(struct nv04_2d_context *ctx, struct nv04_region* dst, int w, int h, unsigned value)
-{
- struct nouveau_channel *chan = ctx->surf2d->channel;
- struct nouveau_grobj *surf2d = ctx->surf2d;
- struct nouveau_grobj *rect = ctx->rect;
- int cs2d_format, gdirect_format;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tFILL_GDIRECT\n");
-#endif
-
- assert(!(dst->pitch & 63) && dst->pitch);
- nv04_region_assert(dst, w, h);
-
- switch(dst->bpps)
- {
- case 0:
- gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
- cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y8;
- break;
- case 1:
- gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A16R5G6B5;
- cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y16;
- break;
- case 2:
- gdirect_format = NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT_A8R8G8B8;
- cs2d_format = NV04_CONTEXT_SURFACES_2D_FORMAT_Y32;
- break;
- default:
- assert(0);
- gdirect_format = 0;
- cs2d_format = 0;
- break;
- }
-
- MARK_RING (chan, 15, 4);
- BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
- OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
- OUT_RELOCo(chan, dst->bo, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
- BEGIN_RING(chan, surf2d, NV04_CONTEXT_SURFACES_2D_FORMAT, 4);
- OUT_RING (chan, cs2d_format);
- OUT_RING (chan, (dst->pitch << 16) | dst->pitch);
- OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
- OUT_RELOCl(chan, dst->bo, dst->offset, NOUVEAU_BO_VRAM | NOUVEAU_BO_WR);
-
- BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR_FORMAT, 1);
- OUT_RING (chan, gdirect_format);
- BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_COLOR1_A, 1);
- OUT_RING (chan, value);
- BEGIN_RING(chan, rect, NV04_GDI_RECTANGLE_TEXT_UNCLIPPED_RECTANGLE_POINT(0), 2);
- OUT_RING (chan, (dst->x << 16) | dst->y);
- OUT_RING (chan, ( w << 16) | h);
-}
-
-int
-nv04_region_fill_2d(struct nv04_2d_context *ctx, struct nv04_region *dst,
- int w, int h, unsigned value)
-{
- if(!w || !h)
- return 0;
-
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "FILL [%i, %i: %i] ", w, h, dst->bpps);
- nv04_region_print(dst);
- fprintf(stderr, " <- 0x%x\n", value);
-#endif
-
- if(nv04_region_is_contiguous(dst, w, h))
- {
- nv04_region_contiguous_shape(dst, &w, &h, 6);
- nv04_region_linearize_contiguous(dst, w, h);
- }
-
- // TODO: maybe do intermediate copies for some cases instead of using the 3D engine/CPU
- /* GdiRect doesn't work together with swzsurf, so the 3D engine, or an intermediate copy, is the only option here */
- if(!dst->pitch)
- {
-#ifdef NV04_REGION_DEBUG
- fprintf(stderr, "\tFILL_ENG3D\n");
-#endif
- return 1;
- }
- else if(!nv04_region_align(dst, w, h, 6))
- {
- nv04_region_fill_gdirect(ctx, dst, w, h, value);
- return 0;
- }
- else
- return -1;
-}
-
-
-void
-nv04_2d_context_takedown(struct nv04_2d_context *ctx)
-{
- nouveau_notifier_free(&ctx->ntfy);
- nouveau_grobj_free(&ctx->m2mf);
- nouveau_grobj_free(&ctx->surf2d);
- nouveau_grobj_free(&ctx->swzsurf);
- nouveau_grobj_free(&ctx->rect);
- nouveau_grobj_free(&ctx->blit);
- nouveau_grobj_free(&ctx->sifm);
-
- free(ctx);
-}
-
-struct nv04_2d_context *
-nv04_2d_context_init(struct nouveau_channel* chan)
-{
- struct nv04_2d_context *ctx = calloc(1, sizeof(struct nv04_2d_context));
- unsigned handle = 0x88000000, class;
- int ret;
-
- if (!ctx)
- return NULL;
-
- ret = nouveau_notifier_alloc(chan, handle++, 1, &ctx->ntfy);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- ret = nouveau_grobj_alloc(chan, handle++, 0x0039, &ctx->m2mf);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- BEGIN_RING(chan, ctx->m2mf, NV04_M2MF_DMA_NOTIFY, 1);
- OUT_RING (chan, ctx->ntfy->handle);
-
- if (chan->device->chipset < 0x10)
- class = NV04_CONTEXT_SURFACES_2D;
- else
- class = NV10_CONTEXT_SURFACES_2D;
-
- ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->surf2d);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- BEGIN_RING(chan, ctx->surf2d,
- NV04_CONTEXT_SURFACES_2D_DMA_IMAGE_SOURCE, 2);
- OUT_RING (chan, chan->vram->handle);
- OUT_RING (chan, chan->vram->handle);
-
- if (chan->device->chipset < 0x10)
- class = NV04_IMAGE_BLIT;
- else
- class = NV11_IMAGE_BLIT;
-
- ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->blit);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_DMA_NOTIFY, 1);
- OUT_RING (chan, ctx->ntfy->handle);
- BEGIN_RING(chan, ctx->blit, NV04_IMAGE_BLIT_SURFACES, 1);
- OUT_RING (chan, ctx->surf2d->handle);
- BEGIN_RING(chan, ctx->blit, NV01_IMAGE_BLIT_OPERATION, 1);
- OUT_RING (chan, NV01_IMAGE_BLIT_OPERATION_SRCCOPY);
-
- ret = nouveau_grobj_alloc(chan, handle++, NV04_GDI_RECTANGLE_TEXT,
- &ctx->rect);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_DMA_NOTIFY, 1);
- OUT_RING (chan, ctx->ntfy->handle);
- BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_SURFACE, 1);
- OUT_RING (chan, ctx->surf2d->handle);
- BEGIN_RING(chan, ctx->rect, NV04_GDI_RECTANGLE_TEXT_OPERATION, 1);
- OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_OPERATION_SRCCOPY);
- BEGIN_RING(chan, ctx->rect,
- NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT, 1);
- OUT_RING (chan, NV04_GDI_RECTANGLE_TEXT_MONOCHROME_FORMAT_LE);
-
- switch (chan->device->chipset & 0xf0) {
- case 0x00:
- case 0x10:
- class = NV04_SWIZZLED_SURFACE;
- break;
- case 0x20:
- class = NV11_SWIZZLED_SURFACE;
- break;
- case 0x30:
- class = NV30_SWIZZLED_SURFACE;
- break;
- case 0x40:
- case 0x60:
- class = NV40_SWIZZLED_SURFACE;
- break;
- default:
- /* Famous last words: this really can't happen.. */
- assert(0);
- break;
- }
-
- ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->swzsurf);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- /* all the Gallium MARK_RING calculations assume no autobinding, so do that now */
- if(ctx->swzsurf->bound == NOUVEAU_GROBJ_UNBOUND)
- nouveau_grobj_autobind(ctx->swzsurf);
-
- switch (chan->device->chipset & 0xf0) {
- case 0x10:
- case 0x20:
- class = NV10_SCALED_IMAGE_FROM_MEMORY;
- break;
- case 0x30:
- class = NV30_SCALED_IMAGE_FROM_MEMORY;
- break;
- case 0x40:
- case 0x60:
- class = NV40_SCALED_IMAGE_FROM_MEMORY;
- break;
- default:
- class = NV04_SCALED_IMAGE_FROM_MEMORY;
- break;
- }
-
- ret = nouveau_grobj_alloc(chan, handle++, class, &ctx->sifm);
- if (ret) {
- nv04_2d_context_takedown(ctx);
- return NULL;
- }
-
- /* all the Gallium MARK_RING calculations assume no autobinding, so do that now */
- if(ctx->sifm->bound == NOUVEAU_GROBJ_UNBOUND)
- nouveau_grobj_autobind(ctx->sifm);
-
- return ctx;
-}