1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright 2012 Red Hat Inc.
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice shall be included in
12bf215546Sopenharmony_ci * all copies or substantial portions of the Software.
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
18bf215546Sopenharmony_ci * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19bf215546Sopenharmony_ci * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20bf215546Sopenharmony_ci * OTHER DEALINGS IN THE SOFTWARE.
21bf215546Sopenharmony_ci *
22bf215546Sopenharmony_ci * Authors: Ben Skeggs
23bf215546Sopenharmony_ci *
24bf215546Sopenharmony_ci */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include "util/format/u_format.h"
27bf215546Sopenharmony_ci#include "util/u_inlines.h"
28bf215546Sopenharmony_ci#include "util/u_surface.h"
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include "nv_m2mf.xml.h"
31bf215546Sopenharmony_ci#include "nv_object.xml.h"
32bf215546Sopenharmony_ci#include "nv30/nv30_screen.h"
33bf215546Sopenharmony_ci#include "nv30/nv30_context.h"
34bf215546Sopenharmony_ci#include "nv30/nv30_resource.h"
35bf215546Sopenharmony_ci#include "nv30/nv30_transfer.h"
36bf215546Sopenharmony_ci
37bf215546Sopenharmony_cistatic inline unsigned
38bf215546Sopenharmony_cilayer_offset(struct pipe_resource *pt, unsigned level, unsigned layer)
39bf215546Sopenharmony_ci{
40bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt);
41bf215546Sopenharmony_ci   struct nv30_miptree_level *lvl = &mt->level[level];
42bf215546Sopenharmony_ci
43bf215546Sopenharmony_ci   if (pt->target == PIPE_TEXTURE_CUBE)
44bf215546Sopenharmony_ci      return (layer * mt->layer_size) + lvl->offset;
45bf215546Sopenharmony_ci
46bf215546Sopenharmony_ci   return lvl->offset + (layer * lvl->zslice_size);
47bf215546Sopenharmony_ci}
48bf215546Sopenharmony_ci
49bf215546Sopenharmony_cibool
50bf215546Sopenharmony_cinv30_miptree_get_handle(struct pipe_screen *pscreen,
51bf215546Sopenharmony_ci                        struct pipe_context *context,
52bf215546Sopenharmony_ci                        struct pipe_resource *pt,
53bf215546Sopenharmony_ci                        struct winsys_handle *handle,
54bf215546Sopenharmony_ci                        unsigned usage)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   if (pt->target == PIPE_BUFFER)
57bf215546Sopenharmony_ci      return false;
58bf215546Sopenharmony_ci
59bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt);
60bf215546Sopenharmony_ci   unsigned stride;
61bf215546Sopenharmony_ci
62bf215546Sopenharmony_ci   if (!mt || !mt->base.bo)
63bf215546Sopenharmony_ci      return false;
64bf215546Sopenharmony_ci
65bf215546Sopenharmony_ci   stride = mt->level[0].pitch;
66bf215546Sopenharmony_ci
67bf215546Sopenharmony_ci   return nouveau_screen_bo_get_handle(pscreen, mt->base.bo, stride, handle);
68bf215546Sopenharmony_ci}
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_civoid
71bf215546Sopenharmony_cinv30_miptree_destroy(struct pipe_screen *pscreen, struct pipe_resource *pt)
72bf215546Sopenharmony_ci{
73bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt);
74bf215546Sopenharmony_ci
75bf215546Sopenharmony_ci   nouveau_bo_ref(NULL, &mt->base.bo);
76bf215546Sopenharmony_ci   FREE(mt);
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_cistruct nv30_transfer {
80bf215546Sopenharmony_ci   struct pipe_transfer base;
81bf215546Sopenharmony_ci   struct nv30_rect img;
82bf215546Sopenharmony_ci   struct nv30_rect tmp;
83bf215546Sopenharmony_ci   unsigned nblocksx;
84bf215546Sopenharmony_ci   unsigned nblocksy;
85bf215546Sopenharmony_ci};
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistatic inline struct nv30_transfer *
88bf215546Sopenharmony_cinv30_transfer(struct pipe_transfer *ptx)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   return (struct nv30_transfer *)ptx;
91bf215546Sopenharmony_ci}
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_cistatic inline void
94bf215546Sopenharmony_cidefine_rect(struct pipe_resource *pt, unsigned level, unsigned z,
95bf215546Sopenharmony_ci            unsigned x, unsigned y, unsigned w, unsigned h,
96bf215546Sopenharmony_ci            struct nv30_rect *rect)
97bf215546Sopenharmony_ci{
98bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt);
99bf215546Sopenharmony_ci   struct nv30_miptree_level *lvl = &mt->level[level];
100bf215546Sopenharmony_ci
101bf215546Sopenharmony_ci   rect->w = u_minify(pt->width0, level) << mt->ms_x;
102bf215546Sopenharmony_ci   rect->w = util_format_get_nblocksx(pt->format, rect->w);
103bf215546Sopenharmony_ci   rect->h = u_minify(pt->height0, level) << mt->ms_y;
104bf215546Sopenharmony_ci   rect->h = util_format_get_nblocksy(pt->format, rect->h);
105bf215546Sopenharmony_ci   rect->d = 1;
106bf215546Sopenharmony_ci   rect->z = 0;
107bf215546Sopenharmony_ci   if (mt->swizzled) {
108bf215546Sopenharmony_ci      if (pt->target == PIPE_TEXTURE_3D) {
109bf215546Sopenharmony_ci         rect->d = u_minify(pt->depth0, level);
110bf215546Sopenharmony_ci         rect->z = z; z = 0;
111bf215546Sopenharmony_ci      }
112bf215546Sopenharmony_ci      rect->pitch = 0;
113bf215546Sopenharmony_ci   } else {
114bf215546Sopenharmony_ci      rect->pitch = lvl->pitch;
115bf215546Sopenharmony_ci   }
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   rect->bo     = mt->base.bo;
118bf215546Sopenharmony_ci   rect->domain = NOUVEAU_BO_VRAM;
119bf215546Sopenharmony_ci   rect->offset = layer_offset(pt, level, z);
120bf215546Sopenharmony_ci   rect->cpp    = util_format_get_blocksize(pt->format);
121bf215546Sopenharmony_ci
122bf215546Sopenharmony_ci   rect->x0     = util_format_get_nblocksx(pt->format, x) << mt->ms_x;
123bf215546Sopenharmony_ci   rect->y0     = util_format_get_nblocksy(pt->format, y) << mt->ms_y;
124bf215546Sopenharmony_ci   rect->x1     = rect->x0 + (util_format_get_nblocksx(pt->format, w) << mt->ms_x);
125bf215546Sopenharmony_ci   rect->y1     = rect->y0 + (util_format_get_nblocksy(pt->format, h) << mt->ms_y);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   /* XXX There's some indication that swizzled formats > 4 bytes are treated
128bf215546Sopenharmony_ci    * differently. However that only applies to RGBA16_FLOAT, RGBA32_FLOAT,
129bf215546Sopenharmony_ci    * and the DXT* formats. The former aren't properly supported yet, and the
130bf215546Sopenharmony_ci    * latter avoid swizzled layouts.
131bf215546Sopenharmony_ci
132bf215546Sopenharmony_ci   if (mt->swizzled && rect->cpp > 4) {
133bf215546Sopenharmony_ci      unsigned scale = rect->cpp / 4;
134bf215546Sopenharmony_ci      rect->w *= scale;
135bf215546Sopenharmony_ci      rect->x0 *= scale;
136bf215546Sopenharmony_ci      rect->x1 *= scale;
137bf215546Sopenharmony_ci      rect->cpp = 4;
138bf215546Sopenharmony_ci   }
139bf215546Sopenharmony_ci   */
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_civoid
143bf215546Sopenharmony_cinv30_resource_copy_region(struct pipe_context *pipe,
144bf215546Sopenharmony_ci                          struct pipe_resource *dstres, unsigned dst_level,
145bf215546Sopenharmony_ci                          unsigned dstx, unsigned dsty, unsigned dstz,
146bf215546Sopenharmony_ci                          struct pipe_resource *srcres, unsigned src_level,
147bf215546Sopenharmony_ci                          const struct pipe_box *src_box)
148bf215546Sopenharmony_ci{
149bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
150bf215546Sopenharmony_ci   struct nv30_rect src, dst;
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci   if (dstres->target == PIPE_BUFFER && srcres->target == PIPE_BUFFER) {
153bf215546Sopenharmony_ci      nouveau_copy_buffer(&nv30->base,
154bf215546Sopenharmony_ci                          nv04_resource(dstres), dstx,
155bf215546Sopenharmony_ci                          nv04_resource(srcres), src_box->x, src_box->width);
156bf215546Sopenharmony_ci      return;
157bf215546Sopenharmony_ci   }
158bf215546Sopenharmony_ci
159bf215546Sopenharmony_ci   define_rect(srcres, src_level, src_box->z, src_box->x, src_box->y,
160bf215546Sopenharmony_ci                       src_box->width, src_box->height, &src);
161bf215546Sopenharmony_ci   define_rect(dstres, dst_level, dstz, dstx, dsty,
162bf215546Sopenharmony_ci                       src_box->width, src_box->height, &dst);
163bf215546Sopenharmony_ci
164bf215546Sopenharmony_ci   nv30_transfer_rect(nv30, NEAREST, &src, &dst);
165bf215546Sopenharmony_ci}
166bf215546Sopenharmony_ci
167bf215546Sopenharmony_cistatic void
168bf215546Sopenharmony_cinv30_resource_resolve(struct nv30_context *nv30,
169bf215546Sopenharmony_ci                      const struct pipe_blit_info *info)
170bf215546Sopenharmony_ci{
171bf215546Sopenharmony_ci   struct nv30_miptree *src_mt = nv30_miptree(info->src.resource);
172bf215546Sopenharmony_ci   struct nv30_rect src, dst;
173bf215546Sopenharmony_ci   unsigned x, x0, x1, y, y1, w, h;
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   define_rect(info->src.resource, 0, info->src.box.z, info->src.box.x,
176bf215546Sopenharmony_ci      info->src.box.y, info->src.box.width, info->src.box.height, &src);
177bf215546Sopenharmony_ci   define_rect(info->dst.resource, 0, info->dst.box.z, info->dst.box.x,
178bf215546Sopenharmony_ci      info->dst.box.y, info->dst.box.width, info->dst.box.height, &dst);
179bf215546Sopenharmony_ci
180bf215546Sopenharmony_ci   x0 = src.x0;
181bf215546Sopenharmony_ci   x1 = src.x1;
182bf215546Sopenharmony_ci   y1 = src.y1;
183bf215546Sopenharmony_ci
184bf215546Sopenharmony_ci   /* On nv3x we must use sifm which is restricted to 1024x1024 tiles */
185bf215546Sopenharmony_ci   for (y = src.y0; y < y1; y += h) {
186bf215546Sopenharmony_ci      h = y1 - y;
187bf215546Sopenharmony_ci      if (h > 1024)
188bf215546Sopenharmony_ci         h = 1024;
189bf215546Sopenharmony_ci
190bf215546Sopenharmony_ci      src.y0 = 0;
191bf215546Sopenharmony_ci      src.y1 = h;
192bf215546Sopenharmony_ci      src.h = h;
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci      dst.y1 = dst.y0 + (h >> src_mt->ms_y);
195bf215546Sopenharmony_ci      dst.h = h >> src_mt->ms_y;
196bf215546Sopenharmony_ci
197bf215546Sopenharmony_ci      for (x = x0; x < x1; x += w) {
198bf215546Sopenharmony_ci         w = x1 - x;
199bf215546Sopenharmony_ci         if (w > 1024)
200bf215546Sopenharmony_ci            w = 1024;
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci         src.offset = y * src.pitch + x * src.cpp;
203bf215546Sopenharmony_ci         src.x0 = 0;
204bf215546Sopenharmony_ci         src.x1 = w;
205bf215546Sopenharmony_ci         src.w = w;
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_ci         dst.offset = (y >> src_mt->ms_y) * dst.pitch +
208bf215546Sopenharmony_ci                      (x >> src_mt->ms_x) * dst.cpp;
209bf215546Sopenharmony_ci         dst.x1 = dst.x0 + (w >> src_mt->ms_x);
210bf215546Sopenharmony_ci         dst.w = w >> src_mt->ms_x;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci         nv30_transfer_rect(nv30, BILINEAR, &src, &dst);
213bf215546Sopenharmony_ci      }
214bf215546Sopenharmony_ci   }
215bf215546Sopenharmony_ci}
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_civoid
218bf215546Sopenharmony_cinv30_blit(struct pipe_context *pipe,
219bf215546Sopenharmony_ci          const struct pipe_blit_info *blit_info)
220bf215546Sopenharmony_ci{
221bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
222bf215546Sopenharmony_ci   struct pipe_blit_info info = *blit_info;
223bf215546Sopenharmony_ci
224bf215546Sopenharmony_ci   if (info.src.resource->nr_samples > 1 &&
225bf215546Sopenharmony_ci       info.dst.resource->nr_samples <= 1 &&
226bf215546Sopenharmony_ci       !util_format_is_depth_or_stencil(info.src.resource->format) &&
227bf215546Sopenharmony_ci       !util_format_is_pure_integer(info.src.resource->format)) {
228bf215546Sopenharmony_ci      nv30_resource_resolve(nv30, blit_info);
229bf215546Sopenharmony_ci      return;
230bf215546Sopenharmony_ci   }
231bf215546Sopenharmony_ci
232bf215546Sopenharmony_ci   if (util_try_blit_via_copy_region(pipe, &info, nv30->render_cond_query != NULL)) {
233bf215546Sopenharmony_ci      return; /* done */
234bf215546Sopenharmony_ci   }
235bf215546Sopenharmony_ci
236bf215546Sopenharmony_ci   if (info.mask & PIPE_MASK_S) {
237bf215546Sopenharmony_ci      debug_printf("nv30: cannot blit stencil, skipping\n");
238bf215546Sopenharmony_ci      info.mask &= ~PIPE_MASK_S;
239bf215546Sopenharmony_ci   }
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   if (!util_blitter_is_blit_supported(nv30->blitter, &info)) {
242bf215546Sopenharmony_ci      debug_printf("nv30: blit unsupported %s -> %s\n",
243bf215546Sopenharmony_ci                   util_format_short_name(info.src.resource->format),
244bf215546Sopenharmony_ci                   util_format_short_name(info.dst.resource->format));
245bf215546Sopenharmony_ci      return;
246bf215546Sopenharmony_ci   }
247bf215546Sopenharmony_ci
248bf215546Sopenharmony_ci   /* XXX turn off occlusion queries */
249bf215546Sopenharmony_ci
250bf215546Sopenharmony_ci   util_blitter_save_vertex_buffer_slot(nv30->blitter, nv30->vtxbuf);
251bf215546Sopenharmony_ci   util_blitter_save_vertex_elements(nv30->blitter, nv30->vertex);
252bf215546Sopenharmony_ci   util_blitter_save_vertex_shader(nv30->blitter, nv30->vertprog.program);
253bf215546Sopenharmony_ci   util_blitter_save_rasterizer(nv30->blitter, nv30->rast);
254bf215546Sopenharmony_ci   util_blitter_save_viewport(nv30->blitter, &nv30->viewport);
255bf215546Sopenharmony_ci   util_blitter_save_scissor(nv30->blitter, &nv30->scissor);
256bf215546Sopenharmony_ci   util_blitter_save_fragment_shader(nv30->blitter, nv30->fragprog.program);
257bf215546Sopenharmony_ci   util_blitter_save_blend(nv30->blitter, nv30->blend);
258bf215546Sopenharmony_ci   util_blitter_save_depth_stencil_alpha(nv30->blitter,
259bf215546Sopenharmony_ci                                         nv30->zsa);
260bf215546Sopenharmony_ci   util_blitter_save_stencil_ref(nv30->blitter, &nv30->stencil_ref);
261bf215546Sopenharmony_ci   util_blitter_save_sample_mask(nv30->blitter, nv30->sample_mask, 0);
262bf215546Sopenharmony_ci   util_blitter_save_framebuffer(nv30->blitter, &nv30->framebuffer);
263bf215546Sopenharmony_ci   util_blitter_save_fragment_sampler_states(nv30->blitter,
264bf215546Sopenharmony_ci                     nv30->fragprog.num_samplers,
265bf215546Sopenharmony_ci                     (void**)nv30->fragprog.samplers);
266bf215546Sopenharmony_ci   util_blitter_save_fragment_sampler_views(nv30->blitter,
267bf215546Sopenharmony_ci                     nv30->fragprog.num_textures, nv30->fragprog.textures);
268bf215546Sopenharmony_ci   util_blitter_save_render_condition(nv30->blitter, nv30->render_cond_query,
269bf215546Sopenharmony_ci                                      nv30->render_cond_cond, nv30->render_cond_mode);
270bf215546Sopenharmony_ci   util_blitter_blit(nv30->blitter, &info);
271bf215546Sopenharmony_ci}
272bf215546Sopenharmony_ci
273bf215546Sopenharmony_civoid
274bf215546Sopenharmony_cinv30_flush_resource(struct pipe_context *pipe,
275bf215546Sopenharmony_ci                    struct pipe_resource *resource)
276bf215546Sopenharmony_ci{
277bf215546Sopenharmony_ci}
278bf215546Sopenharmony_ci
279bf215546Sopenharmony_civoid *
280bf215546Sopenharmony_cinv30_miptree_transfer_map(struct pipe_context *pipe, struct pipe_resource *pt,
281bf215546Sopenharmony_ci                          unsigned level, unsigned usage,
282bf215546Sopenharmony_ci                          const struct pipe_box *box,
283bf215546Sopenharmony_ci                          struct pipe_transfer **ptransfer)
284bf215546Sopenharmony_ci{
285bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
286bf215546Sopenharmony_ci   struct nouveau_device *dev = nv30->screen->base.device;
287bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt);
288bf215546Sopenharmony_ci   struct nv30_transfer *tx;
289bf215546Sopenharmony_ci   unsigned access = 0;
290bf215546Sopenharmony_ci   int ret;
291bf215546Sopenharmony_ci
292bf215546Sopenharmony_ci   tx = CALLOC_STRUCT(nv30_transfer);
293bf215546Sopenharmony_ci   if (!tx)
294bf215546Sopenharmony_ci      return NULL;
295bf215546Sopenharmony_ci   pipe_resource_reference(&tx->base.resource, pt);
296bf215546Sopenharmony_ci   tx->base.level = level;
297bf215546Sopenharmony_ci   tx->base.usage = usage;
298bf215546Sopenharmony_ci   tx->base.box = *box;
299bf215546Sopenharmony_ci   tx->base.stride = align(util_format_get_nblocksx(pt->format, box->width) *
300bf215546Sopenharmony_ci                           util_format_get_blocksize(pt->format), 64);
301bf215546Sopenharmony_ci   tx->base.layer_stride = util_format_get_nblocksy(pt->format, box->height) *
302bf215546Sopenharmony_ci                           tx->base.stride;
303bf215546Sopenharmony_ci
304bf215546Sopenharmony_ci   tx->nblocksx = util_format_get_nblocksx(pt->format, box->width);
305bf215546Sopenharmony_ci   tx->nblocksy = util_format_get_nblocksy(pt->format, box->height);
306bf215546Sopenharmony_ci
307bf215546Sopenharmony_ci   define_rect(pt, level, box->z, box->x, box->y,
308bf215546Sopenharmony_ci               box->width, box->height, &tx->img);
309bf215546Sopenharmony_ci
310bf215546Sopenharmony_ci   ret = nouveau_bo_new(dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0,
311bf215546Sopenharmony_ci                        tx->base.layer_stride * tx->base.box.depth, NULL,
312bf215546Sopenharmony_ci                        &tx->tmp.bo);
313bf215546Sopenharmony_ci   if (ret) {
314bf215546Sopenharmony_ci      pipe_resource_reference(&tx->base.resource, NULL);
315bf215546Sopenharmony_ci      FREE(tx);
316bf215546Sopenharmony_ci      return NULL;
317bf215546Sopenharmony_ci   }
318bf215546Sopenharmony_ci
319bf215546Sopenharmony_ci   tx->tmp.domain = NOUVEAU_BO_GART;
320bf215546Sopenharmony_ci   tx->tmp.offset = 0;
321bf215546Sopenharmony_ci   tx->tmp.pitch  = tx->base.stride;
322bf215546Sopenharmony_ci   tx->tmp.cpp    = tx->img.cpp;
323bf215546Sopenharmony_ci   tx->tmp.w      = tx->nblocksx;
324bf215546Sopenharmony_ci   tx->tmp.h      = tx->nblocksy;
325bf215546Sopenharmony_ci   tx->tmp.d      = 1;
326bf215546Sopenharmony_ci   tx->tmp.x0     = 0;
327bf215546Sopenharmony_ci   tx->tmp.y0     = 0;
328bf215546Sopenharmony_ci   tx->tmp.x1     = tx->tmp.w;
329bf215546Sopenharmony_ci   tx->tmp.y1     = tx->tmp.h;
330bf215546Sopenharmony_ci   tx->tmp.z      = 0;
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   if (usage & PIPE_MAP_READ) {
333bf215546Sopenharmony_ci      bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
334bf215546Sopenharmony_ci      unsigned offset = tx->img.offset;
335bf215546Sopenharmony_ci      unsigned z = tx->img.z;
336bf215546Sopenharmony_ci      unsigned i;
337bf215546Sopenharmony_ci      for (i = 0; i < box->depth; ++i) {
338bf215546Sopenharmony_ci         nv30_transfer_rect(nv30, NEAREST, &tx->img, &tx->tmp);
339bf215546Sopenharmony_ci         if (is_3d && mt->swizzled)
340bf215546Sopenharmony_ci            tx->img.z++;
341bf215546Sopenharmony_ci         else if (is_3d)
342bf215546Sopenharmony_ci            tx->img.offset += mt->level[level].zslice_size;
343bf215546Sopenharmony_ci         else
344bf215546Sopenharmony_ci            tx->img.offset += mt->layer_size;
345bf215546Sopenharmony_ci         tx->tmp.offset += tx->base.layer_stride;
346bf215546Sopenharmony_ci      }
347bf215546Sopenharmony_ci      tx->img.z = z;
348bf215546Sopenharmony_ci      tx->img.offset = offset;
349bf215546Sopenharmony_ci      tx->tmp.offset = 0;
350bf215546Sopenharmony_ci   }
351bf215546Sopenharmony_ci
352bf215546Sopenharmony_ci   if (tx->tmp.bo->map) {
353bf215546Sopenharmony_ci      *ptransfer = &tx->base;
354bf215546Sopenharmony_ci      return tx->tmp.bo->map;
355bf215546Sopenharmony_ci   }
356bf215546Sopenharmony_ci
357bf215546Sopenharmony_ci   if (usage & PIPE_MAP_READ)
358bf215546Sopenharmony_ci      access |= NOUVEAU_BO_RD;
359bf215546Sopenharmony_ci   if (usage & PIPE_MAP_WRITE)
360bf215546Sopenharmony_ci      access |= NOUVEAU_BO_WR;
361bf215546Sopenharmony_ci
362bf215546Sopenharmony_ci   ret = nouveau_bo_map(tx->tmp.bo, access, nv30->base.client);
363bf215546Sopenharmony_ci   if (ret) {
364bf215546Sopenharmony_ci      pipe_resource_reference(&tx->base.resource, NULL);
365bf215546Sopenharmony_ci      FREE(tx);
366bf215546Sopenharmony_ci      return NULL;
367bf215546Sopenharmony_ci   }
368bf215546Sopenharmony_ci
369bf215546Sopenharmony_ci   *ptransfer = &tx->base;
370bf215546Sopenharmony_ci   return tx->tmp.bo->map;
371bf215546Sopenharmony_ci}
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_civoid
374bf215546Sopenharmony_cinv30_miptree_transfer_unmap(struct pipe_context *pipe,
375bf215546Sopenharmony_ci                            struct pipe_transfer *ptx)
376bf215546Sopenharmony_ci{
377bf215546Sopenharmony_ci   struct nv30_context *nv30 = nv30_context(pipe);
378bf215546Sopenharmony_ci   struct nv30_transfer *tx = nv30_transfer(ptx);
379bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(tx->base.resource);
380bf215546Sopenharmony_ci   unsigned i;
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci   if (ptx->usage & PIPE_MAP_WRITE) {
383bf215546Sopenharmony_ci      bool is_3d = mt->base.base.target == PIPE_TEXTURE_3D;
384bf215546Sopenharmony_ci      for (i = 0; i < tx->base.box.depth; ++i) {
385bf215546Sopenharmony_ci         nv30_transfer_rect(nv30, NEAREST, &tx->tmp, &tx->img);
386bf215546Sopenharmony_ci         if (is_3d && mt->swizzled)
387bf215546Sopenharmony_ci            tx->img.z++;
388bf215546Sopenharmony_ci         else if (is_3d)
389bf215546Sopenharmony_ci            tx->img.offset += mt->level[tx->base.level].zslice_size;
390bf215546Sopenharmony_ci         else
391bf215546Sopenharmony_ci            tx->img.offset += mt->layer_size;
392bf215546Sopenharmony_ci         tx->tmp.offset += tx->base.layer_stride;
393bf215546Sopenharmony_ci      }
394bf215546Sopenharmony_ci
395bf215546Sopenharmony_ci      /* Allow the copies above to finish executing before freeing the source */
396bf215546Sopenharmony_ci      nouveau_fence_work(nv30->screen->base.fence.current,
397bf215546Sopenharmony_ci                         nouveau_fence_unref_bo, tx->tmp.bo);
398bf215546Sopenharmony_ci   } else {
399bf215546Sopenharmony_ci      nouveau_bo_ref(NULL, &tx->tmp.bo);
400bf215546Sopenharmony_ci   }
401bf215546Sopenharmony_ci   pipe_resource_reference(&ptx->resource, NULL);
402bf215546Sopenharmony_ci   FREE(tx);
403bf215546Sopenharmony_ci}
404bf215546Sopenharmony_ci
405bf215546Sopenharmony_cistruct pipe_resource *
406bf215546Sopenharmony_cinv30_miptree_create(struct pipe_screen *pscreen,
407bf215546Sopenharmony_ci                    const struct pipe_resource *tmpl)
408bf215546Sopenharmony_ci{
409bf215546Sopenharmony_ci   struct nouveau_device *dev = nouveau_screen(pscreen)->device;
410bf215546Sopenharmony_ci   struct nv30_miptree *mt = CALLOC_STRUCT(nv30_miptree);
411bf215546Sopenharmony_ci   struct pipe_resource *pt = &mt->base.base;
412bf215546Sopenharmony_ci   unsigned blocksz, size;
413bf215546Sopenharmony_ci   unsigned w, h, d, l;
414bf215546Sopenharmony_ci   int ret;
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   switch (tmpl->nr_samples) {
417bf215546Sopenharmony_ci   case 4:
418bf215546Sopenharmony_ci      mt->ms_mode = 0x00004000;
419bf215546Sopenharmony_ci      mt->ms_x = 1;
420bf215546Sopenharmony_ci      mt->ms_y = 1;
421bf215546Sopenharmony_ci      break;
422bf215546Sopenharmony_ci   case 2:
423bf215546Sopenharmony_ci      mt->ms_mode = 0x00003000;
424bf215546Sopenharmony_ci      mt->ms_x = 1;
425bf215546Sopenharmony_ci      mt->ms_y = 0;
426bf215546Sopenharmony_ci      break;
427bf215546Sopenharmony_ci   default:
428bf215546Sopenharmony_ci      mt->ms_mode = 0x00000000;
429bf215546Sopenharmony_ci      mt->ms_x = 0;
430bf215546Sopenharmony_ci      mt->ms_y = 0;
431bf215546Sopenharmony_ci      break;
432bf215546Sopenharmony_ci   }
433bf215546Sopenharmony_ci
434bf215546Sopenharmony_ci   *pt = *tmpl;
435bf215546Sopenharmony_ci   pipe_reference_init(&pt->reference, 1);
436bf215546Sopenharmony_ci   pt->screen = pscreen;
437bf215546Sopenharmony_ci
438bf215546Sopenharmony_ci   w = pt->width0 << mt->ms_x;
439bf215546Sopenharmony_ci   h = pt->height0 << mt->ms_y;
440bf215546Sopenharmony_ci   d = (pt->target == PIPE_TEXTURE_3D) ? pt->depth0 : 1;
441bf215546Sopenharmony_ci   blocksz = util_format_get_blocksize(pt->format);
442bf215546Sopenharmony_ci
443bf215546Sopenharmony_ci   if ((pt->target == PIPE_TEXTURE_RECT) ||
444bf215546Sopenharmony_ci       (pt->bind & PIPE_BIND_SCANOUT) ||
445bf215546Sopenharmony_ci       !util_is_power_of_two_or_zero(pt->width0) ||
446bf215546Sopenharmony_ci       !util_is_power_of_two_or_zero(pt->height0) ||
447bf215546Sopenharmony_ci       !util_is_power_of_two_or_zero(pt->depth0) ||
448bf215546Sopenharmony_ci       mt->ms_mode) {
449bf215546Sopenharmony_ci      mt->uniform_pitch = util_format_get_nblocksx(pt->format, w) * blocksz;
450bf215546Sopenharmony_ci      mt->uniform_pitch = align(mt->uniform_pitch, 64);
451bf215546Sopenharmony_ci      if (pt->bind & PIPE_BIND_SCANOUT) {
452bf215546Sopenharmony_ci         struct nv30_screen *screen = nv30_screen(pscreen);
453bf215546Sopenharmony_ci         int pitch_align = MAX2(
454bf215546Sopenharmony_ci               screen->eng3d->oclass >= NV40_3D_CLASS ? 1024 : 256,
455bf215546Sopenharmony_ci               /* round_down_pow2(mt->uniform_pitch / 4) */
456bf215546Sopenharmony_ci               1 << (util_last_bit(mt->uniform_pitch / 4) - 1));
457bf215546Sopenharmony_ci         mt->uniform_pitch = align(mt->uniform_pitch, pitch_align);
458bf215546Sopenharmony_ci      }
459bf215546Sopenharmony_ci   }
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_ci   if (util_format_is_compressed(pt->format)) {
462bf215546Sopenharmony_ci      // Compressed (DXT) formats are packed tightly. We don't mark them as
463bf215546Sopenharmony_ci      // swizzled, since their layout is largely linear. However we do end up
464bf215546Sopenharmony_ci      // omitting the LINEAR flag when texturing them, as the levels are not
465bf215546Sopenharmony_ci      // uniformly sized (for POT sizes).
466bf215546Sopenharmony_ci   } else if (!mt->uniform_pitch) {
467bf215546Sopenharmony_ci      mt->swizzled = true;
468bf215546Sopenharmony_ci   }
469bf215546Sopenharmony_ci
470bf215546Sopenharmony_ci   size = 0;
471bf215546Sopenharmony_ci   for (l = 0; l <= pt->last_level; l++) {
472bf215546Sopenharmony_ci      struct nv30_miptree_level *lvl = &mt->level[l];
473bf215546Sopenharmony_ci      unsigned nbx = util_format_get_nblocksx(pt->format, w);
474bf215546Sopenharmony_ci      unsigned nby = util_format_get_nblocksy(pt->format, h);
475bf215546Sopenharmony_ci
476bf215546Sopenharmony_ci      lvl->offset = size;
477bf215546Sopenharmony_ci      lvl->pitch  = mt->uniform_pitch;
478bf215546Sopenharmony_ci      if (!lvl->pitch)
479bf215546Sopenharmony_ci         lvl->pitch = nbx * blocksz;
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci      lvl->zslice_size = lvl->pitch * nby;
482bf215546Sopenharmony_ci      size += lvl->zslice_size * d;
483bf215546Sopenharmony_ci
484bf215546Sopenharmony_ci      w = u_minify(w, 1);
485bf215546Sopenharmony_ci      h = u_minify(h, 1);
486bf215546Sopenharmony_ci      d = u_minify(d, 1);
487bf215546Sopenharmony_ci   }
488bf215546Sopenharmony_ci
489bf215546Sopenharmony_ci   mt->layer_size = size;
490bf215546Sopenharmony_ci   if (pt->target == PIPE_TEXTURE_CUBE) {
491bf215546Sopenharmony_ci      if (!mt->uniform_pitch)
492bf215546Sopenharmony_ci         mt->layer_size = align(mt->layer_size, 128);
493bf215546Sopenharmony_ci      size = mt->layer_size * 6;
494bf215546Sopenharmony_ci   }
495bf215546Sopenharmony_ci
496bf215546Sopenharmony_ci   ret = nouveau_bo_new(dev, NOUVEAU_BO_VRAM, 256, size, NULL, &mt->base.bo);
497bf215546Sopenharmony_ci   if (ret) {
498bf215546Sopenharmony_ci      FREE(mt);
499bf215546Sopenharmony_ci      return NULL;
500bf215546Sopenharmony_ci   }
501bf215546Sopenharmony_ci
502bf215546Sopenharmony_ci   mt->base.domain = NOUVEAU_BO_VRAM;
503bf215546Sopenharmony_ci   return &mt->base.base;
504bf215546Sopenharmony_ci}
505bf215546Sopenharmony_ci
506bf215546Sopenharmony_cistruct pipe_resource *
507bf215546Sopenharmony_cinv30_miptree_from_handle(struct pipe_screen *pscreen,
508bf215546Sopenharmony_ci                         const struct pipe_resource *tmpl,
509bf215546Sopenharmony_ci                         struct winsys_handle *handle)
510bf215546Sopenharmony_ci{
511bf215546Sopenharmony_ci   struct nv30_miptree *mt;
512bf215546Sopenharmony_ci   unsigned stride;
513bf215546Sopenharmony_ci
514bf215546Sopenharmony_ci   /* only supports 2D, non-mipmapped textures for the moment */
515bf215546Sopenharmony_ci   if ((tmpl->target != PIPE_TEXTURE_2D &&
516bf215546Sopenharmony_ci        tmpl->target != PIPE_TEXTURE_RECT) ||
517bf215546Sopenharmony_ci       tmpl->last_level != 0 ||
518bf215546Sopenharmony_ci       tmpl->depth0 != 1 ||
519bf215546Sopenharmony_ci       tmpl->array_size > 1)
520bf215546Sopenharmony_ci      return NULL;
521bf215546Sopenharmony_ci
522bf215546Sopenharmony_ci   mt = CALLOC_STRUCT(nv30_miptree);
523bf215546Sopenharmony_ci   if (!mt)
524bf215546Sopenharmony_ci      return NULL;
525bf215546Sopenharmony_ci
526bf215546Sopenharmony_ci   mt->base.bo = nouveau_screen_bo_from_handle(pscreen, handle, &stride);
527bf215546Sopenharmony_ci   if (mt->base.bo == NULL) {
528bf215546Sopenharmony_ci      FREE(mt);
529bf215546Sopenharmony_ci      return NULL;
530bf215546Sopenharmony_ci   }
531bf215546Sopenharmony_ci
532bf215546Sopenharmony_ci   mt->base.base = *tmpl;
533bf215546Sopenharmony_ci   pipe_reference_init(&mt->base.base.reference, 1);
534bf215546Sopenharmony_ci   mt->base.base.screen = pscreen;
535bf215546Sopenharmony_ci   mt->uniform_pitch = stride;
536bf215546Sopenharmony_ci   mt->level[0].pitch = mt->uniform_pitch;
537bf215546Sopenharmony_ci   mt->level[0].offset = 0;
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   /* no need to adjust bo reference count */
540bf215546Sopenharmony_ci   return &mt->base.base;
541bf215546Sopenharmony_ci}
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_cistruct pipe_surface *
544bf215546Sopenharmony_cinv30_miptree_surface_new(struct pipe_context *pipe,
545bf215546Sopenharmony_ci                         struct pipe_resource *pt,
546bf215546Sopenharmony_ci                         const struct pipe_surface *tmpl)
547bf215546Sopenharmony_ci{
548bf215546Sopenharmony_ci   struct nv30_miptree *mt = nv30_miptree(pt); /* guaranteed */
549bf215546Sopenharmony_ci   struct nv30_surface *ns;
550bf215546Sopenharmony_ci   struct pipe_surface *ps;
551bf215546Sopenharmony_ci   struct nv30_miptree_level *lvl = &mt->level[tmpl->u.tex.level];
552bf215546Sopenharmony_ci
553bf215546Sopenharmony_ci   ns = CALLOC_STRUCT(nv30_surface);
554bf215546Sopenharmony_ci   if (!ns)
555bf215546Sopenharmony_ci      return NULL;
556bf215546Sopenharmony_ci   ps = &ns->base;
557bf215546Sopenharmony_ci
558bf215546Sopenharmony_ci   pipe_reference_init(&ps->reference, 1);
559bf215546Sopenharmony_ci   pipe_resource_reference(&ps->texture, pt);
560bf215546Sopenharmony_ci   ps->context = pipe;
561bf215546Sopenharmony_ci   ps->format = tmpl->format;
562bf215546Sopenharmony_ci   ps->u.tex.level = tmpl->u.tex.level;
563bf215546Sopenharmony_ci   ps->u.tex.first_layer = tmpl->u.tex.first_layer;
564bf215546Sopenharmony_ci   ps->u.tex.last_layer = tmpl->u.tex.last_layer;
565bf215546Sopenharmony_ci
566bf215546Sopenharmony_ci   ns->width = u_minify(pt->width0, ps->u.tex.level);
567bf215546Sopenharmony_ci   ns->height = u_minify(pt->height0, ps->u.tex.level);
568bf215546Sopenharmony_ci   ns->depth = ps->u.tex.last_layer - ps->u.tex.first_layer + 1;
569bf215546Sopenharmony_ci   ns->offset = layer_offset(pt, ps->u.tex.level, ps->u.tex.first_layer);
570bf215546Sopenharmony_ci   if (mt->swizzled)
571bf215546Sopenharmony_ci      ns->pitch = 4096; /* random, just something the hw won't reject.. */
572bf215546Sopenharmony_ci   else
573bf215546Sopenharmony_ci      ns->pitch = lvl->pitch;
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_ci   /* comment says there are going to be removed, but they're used by the st */
576bf215546Sopenharmony_ci   ps->width = ns->width;
577bf215546Sopenharmony_ci   ps->height = ns->height;
578bf215546Sopenharmony_ci   return ps;
579bf215546Sopenharmony_ci}
580bf215546Sopenharmony_ci
581bf215546Sopenharmony_civoid
582bf215546Sopenharmony_cinv30_miptree_surface_del(struct pipe_context *pipe, struct pipe_surface *ps)
583bf215546Sopenharmony_ci{
584bf215546Sopenharmony_ci   struct nv30_surface *ns = nv30_surface(ps);
585bf215546Sopenharmony_ci
586bf215546Sopenharmony_ci   pipe_resource_reference(&ps->texture, NULL);
587bf215546Sopenharmony_ci   FREE(ns);
588bf215546Sopenharmony_ci}
589