1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2006 VMware, Inc.
4bf215546Sopenharmony_ci * All Rights Reserved.
5bf215546Sopenharmony_ci *
6bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
7bf215546Sopenharmony_ci * copy of this software and associated documentation files (the
8bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
9bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
10bf215546Sopenharmony_ci * distribute, sub license, and/or sell copies of the Software, and to
11bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
12bf215546Sopenharmony_ci * the following conditions:
13bf215546Sopenharmony_ci *
14bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
15bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial portions
16bf215546Sopenharmony_ci * of the Software.
17bf215546Sopenharmony_ci *
18bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19bf215546Sopenharmony_ci * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21bf215546Sopenharmony_ci * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22bf215546Sopenharmony_ci * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23bf215546Sopenharmony_ci * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24bf215546Sopenharmony_ci * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25bf215546Sopenharmony_ci *
26bf215546Sopenharmony_ci **************************************************************************/
27bf215546Sopenharmony_ci/*
28bf215546Sopenharmony_ci * Authors:
29bf215546Sopenharmony_ci *   Keith Whitwell <keithw@vmware.com>
30bf215546Sopenharmony_ci *   Michel Dänzer <daenzer@vmware.com>
31bf215546Sopenharmony_ci */
32bf215546Sopenharmony_ci
33bf215546Sopenharmony_ci#include "pipe/p_context.h"
34bf215546Sopenharmony_ci#include "pipe/p_defines.h"
35bf215546Sopenharmony_ci#include "pipe/p_state.h"
36bf215546Sopenharmony_ci#include "util/format/u_format.h"
37bf215546Sopenharmony_ci#include "util/u_inlines.h"
38bf215546Sopenharmony_ci#include "util/u_math.h"
39bf215546Sopenharmony_ci#include "util/u_memory.h"
40bf215546Sopenharmony_ci#include "util/u_rect.h"
41bf215546Sopenharmony_ci
42bf215546Sopenharmony_ci#include "i915_context.h"
43bf215546Sopenharmony_ci#include "i915_debug.h"
44bf215546Sopenharmony_ci#include "i915_resource.h"
45bf215546Sopenharmony_ci#include "i915_screen.h"
46bf215546Sopenharmony_ci#include "i915_winsys.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_ci#define DEBUG_TEXTURES 0
49bf215546Sopenharmony_ci
50bf215546Sopenharmony_ci/*
51bf215546Sopenharmony_ci * Helper function and arrays
52bf215546Sopenharmony_ci */
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ci/**
55bf215546Sopenharmony_ci * Initial offset for Cube map.
56bf215546Sopenharmony_ci */
57bf215546Sopenharmony_cistatic const int initial_offsets[6][2] = {
58bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_X] = {0, 0}, [PIPE_TEX_FACE_POS_Y] = {1, 0},
59bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_Z] = {1, 1}, [PIPE_TEX_FACE_NEG_X] = {0, 2},
60bf215546Sopenharmony_ci   [PIPE_TEX_FACE_NEG_Y] = {1, 2}, [PIPE_TEX_FACE_NEG_Z] = {1, 3},
61bf215546Sopenharmony_ci};
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_ci/**
64bf215546Sopenharmony_ci * Step offsets for Cube map.
65bf215546Sopenharmony_ci */
66bf215546Sopenharmony_cistatic const int step_offsets[6][2] = {
67bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_X] = {0, 2},  [PIPE_TEX_FACE_POS_Y] = {-1, 2},
68bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_Z] = {-1, 1}, [PIPE_TEX_FACE_NEG_X] = {0, 2},
69bf215546Sopenharmony_ci   [PIPE_TEX_FACE_NEG_Y] = {-1, 2}, [PIPE_TEX_FACE_NEG_Z] = {-1, 1},
70bf215546Sopenharmony_ci};
71bf215546Sopenharmony_ci
72bf215546Sopenharmony_ci/**
73bf215546Sopenharmony_ci * For compressed level 2
74bf215546Sopenharmony_ci */
75bf215546Sopenharmony_cistatic const int bottom_offsets[6] = {
76bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_X] = 16 + 0 * 8, [PIPE_TEX_FACE_POS_Y] = 16 + 1 * 8,
77bf215546Sopenharmony_ci   [PIPE_TEX_FACE_POS_Z] = 16 + 2 * 8, [PIPE_TEX_FACE_NEG_X] = 16 + 3 * 8,
78bf215546Sopenharmony_ci   [PIPE_TEX_FACE_NEG_Y] = 16 + 4 * 8, [PIPE_TEX_FACE_NEG_Z] = 16 + 5 * 8,
79bf215546Sopenharmony_ci};
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_cistatic inline unsigned
82bf215546Sopenharmony_cialign_nblocksx(enum pipe_format format, unsigned width, unsigned align_to)
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   return align(util_format_get_nblocksx(format, width), align_to);
85bf215546Sopenharmony_ci}
86bf215546Sopenharmony_ci
87bf215546Sopenharmony_cistatic inline unsigned
88bf215546Sopenharmony_cialign_nblocksy(enum pipe_format format, unsigned width, unsigned align_to)
89bf215546Sopenharmony_ci{
90bf215546Sopenharmony_ci   return align(util_format_get_nblocksy(format, width), align_to);
91bf215546Sopenharmony_ci}
92bf215546Sopenharmony_ci
93bf215546Sopenharmony_cistatic inline unsigned
94bf215546Sopenharmony_ciget_pot_stride(enum pipe_format format, unsigned width)
95bf215546Sopenharmony_ci{
96bf215546Sopenharmony_ci   return util_next_power_of_two(util_format_get_stride(format, width));
97bf215546Sopenharmony_ci}
98bf215546Sopenharmony_ci
99bf215546Sopenharmony_cistatic inline const char *
100bf215546Sopenharmony_ciget_tiling_string(enum i915_winsys_buffer_tile tile)
101bf215546Sopenharmony_ci{
102bf215546Sopenharmony_ci   switch (tile) {
103bf215546Sopenharmony_ci   case I915_TILE_NONE:
104bf215546Sopenharmony_ci      return "none";
105bf215546Sopenharmony_ci   case I915_TILE_X:
106bf215546Sopenharmony_ci      return "x";
107bf215546Sopenharmony_ci   case I915_TILE_Y:
108bf215546Sopenharmony_ci      return "y";
109bf215546Sopenharmony_ci   default:
110bf215546Sopenharmony_ci      assert(false);
111bf215546Sopenharmony_ci      return "?";
112bf215546Sopenharmony_ci   }
113bf215546Sopenharmony_ci}
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci/*
116bf215546Sopenharmony_ci * More advanced helper funcs
117bf215546Sopenharmony_ci */
118bf215546Sopenharmony_ci
119bf215546Sopenharmony_cistatic void
120bf215546Sopenharmony_cii915_texture_set_level_info(struct i915_texture *tex, unsigned level,
121bf215546Sopenharmony_ci                            unsigned nr_images)
122bf215546Sopenharmony_ci{
123bf215546Sopenharmony_ci   assert(level < ARRAY_SIZE(tex->nr_images));
124bf215546Sopenharmony_ci   assert(nr_images);
125bf215546Sopenharmony_ci   assert(!tex->image_offset[level]);
126bf215546Sopenharmony_ci
127bf215546Sopenharmony_ci   tex->nr_images[level] = nr_images;
128bf215546Sopenharmony_ci   tex->image_offset[level] = MALLOC(nr_images * sizeof(struct offset_pair));
129bf215546Sopenharmony_ci   tex->image_offset[level][0].nblocksx = 0;
130bf215546Sopenharmony_ci   tex->image_offset[level][0].nblocksy = 0;
131bf215546Sopenharmony_ci}
132bf215546Sopenharmony_ci
133bf215546Sopenharmony_ciunsigned
134bf215546Sopenharmony_cii915_texture_offset(const struct i915_texture *tex, unsigned level,
135bf215546Sopenharmony_ci                    unsigned layer)
136bf215546Sopenharmony_ci{
137bf215546Sopenharmony_ci   unsigned x, y;
138bf215546Sopenharmony_ci   x = tex->image_offset[level][layer].nblocksx *
139bf215546Sopenharmony_ci       util_format_get_blocksize(tex->b.format);
140bf215546Sopenharmony_ci   y = tex->image_offset[level][layer].nblocksy;
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci   return y * tex->stride + x;
143bf215546Sopenharmony_ci}
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cistatic void
146bf215546Sopenharmony_cii915_texture_set_image_offset(struct i915_texture *tex, unsigned level,
147bf215546Sopenharmony_ci                              unsigned img, unsigned nblocksx,
148bf215546Sopenharmony_ci                              unsigned nblocksy)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   /* for the first image and level make sure offset is zero */
151bf215546Sopenharmony_ci   assert(!(img == 0 && level == 0) || (nblocksx == 0 && nblocksy == 0));
152bf215546Sopenharmony_ci   assert(img < tex->nr_images[level]);
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_ci   tex->image_offset[level][img].nblocksx = nblocksx;
155bf215546Sopenharmony_ci   tex->image_offset[level][img].nblocksy = nblocksy;
156bf215546Sopenharmony_ci
157bf215546Sopenharmony_ci#if DEBUG_TEXTURES
158bf215546Sopenharmony_ci   debug_printf("%s: %p level %u, img %u (%u, %u)\n", __FUNCTION__, tex, level,
159bf215546Sopenharmony_ci                img, x, y);
160bf215546Sopenharmony_ci#endif
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_cistatic enum i915_winsys_buffer_tile
164bf215546Sopenharmony_cii915_texture_tiling(struct i915_screen *is, struct i915_texture *tex)
165bf215546Sopenharmony_ci{
166bf215546Sopenharmony_ci   if (!is->debug.tiling)
167bf215546Sopenharmony_ci      return I915_TILE_NONE;
168bf215546Sopenharmony_ci
169bf215546Sopenharmony_ci   if (tex->b.target == PIPE_TEXTURE_1D)
170bf215546Sopenharmony_ci      return I915_TILE_NONE;
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci   if (util_format_is_compressed(tex->b.format))
173bf215546Sopenharmony_ci      return I915_TILE_X;
174bf215546Sopenharmony_ci
175bf215546Sopenharmony_ci   if (is->debug.use_blitter)
176bf215546Sopenharmony_ci      return I915_TILE_X;
177bf215546Sopenharmony_ci   else
178bf215546Sopenharmony_ci      return I915_TILE_Y;
179bf215546Sopenharmony_ci}
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci/*
182bf215546Sopenharmony_ci * Shared layout functions
183bf215546Sopenharmony_ci */
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci/**
186bf215546Sopenharmony_ci * Special case to deal with scanout textures.
187bf215546Sopenharmony_ci */
188bf215546Sopenharmony_cistatic bool
189bf215546Sopenharmony_cii9x5_scanout_layout(struct i915_texture *tex)
190bf215546Sopenharmony_ci{
191bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
192bf215546Sopenharmony_ci
193bf215546Sopenharmony_ci   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
194bf215546Sopenharmony_ci      return false;
195bf215546Sopenharmony_ci
196bf215546Sopenharmony_ci   if (pt->width0 >= 240) {
197bf215546Sopenharmony_ci      tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
198bf215546Sopenharmony_ci      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
199bf215546Sopenharmony_ci      tex->tiling = I915_TILE_X;
200bf215546Sopenharmony_ci      /* special case for cursors */
201bf215546Sopenharmony_ci   } else if (pt->width0 == 64 && pt->height0 == 64) {
202bf215546Sopenharmony_ci      tex->stride = get_pot_stride(pt->format, pt->width0);
203bf215546Sopenharmony_ci      tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
204bf215546Sopenharmony_ci   } else {
205bf215546Sopenharmony_ci      return false;
206bf215546Sopenharmony_ci   }
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci   i915_texture_set_level_info(tex, 0, 1);
209bf215546Sopenharmony_ci   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
210bf215546Sopenharmony_ci
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci#if DEBUG_TEXTURE
213bf215546Sopenharmony_ci   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
214bf215546Sopenharmony_ci                pt->width0, pt->height0, util_format_get_blocksize(pt->format),
215bf215546Sopenharmony_ci                tex->stride, tex->total_nblocksy,
216bf215546Sopenharmony_ci                tex->stride * tex->total_nblocksy);
217bf215546Sopenharmony_ci#endif
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   return true;
220bf215546Sopenharmony_ci}
221bf215546Sopenharmony_ci
222bf215546Sopenharmony_ci/**
223bf215546Sopenharmony_ci * Special case to deal with shared textures.
224bf215546Sopenharmony_ci */
225bf215546Sopenharmony_cistatic bool
226bf215546Sopenharmony_cii9x5_display_target_layout(struct i915_texture *tex)
227bf215546Sopenharmony_ci{
228bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
229bf215546Sopenharmony_ci
230bf215546Sopenharmony_ci   if (pt->last_level > 0 || util_format_get_blocksize(pt->format) != 4)
231bf215546Sopenharmony_ci      return false;
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   /* fallback to normal textures for small textures */
234bf215546Sopenharmony_ci   if (pt->width0 < 240)
235bf215546Sopenharmony_ci      return false;
236bf215546Sopenharmony_ci
237bf215546Sopenharmony_ci   i915_texture_set_level_info(tex, 0, 1);
238bf215546Sopenharmony_ci   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
239bf215546Sopenharmony_ci
240bf215546Sopenharmony_ci   tex->stride = align(util_format_get_stride(pt->format, pt->width0), 64);
241bf215546Sopenharmony_ci   tex->total_nblocksy = align_nblocksy(pt->format, pt->height0, 8);
242bf215546Sopenharmony_ci   tex->tiling = I915_TILE_X;
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_ci#if DEBUG_TEXTURE
245bf215546Sopenharmony_ci   debug_printf("%s size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__,
246bf215546Sopenharmony_ci                pt->width0, pt->height0, util_format_get_blocksize(pt->format),
247bf215546Sopenharmony_ci                tex->stride, tex->total_nblocksy,
248bf215546Sopenharmony_ci                tex->stride * tex->total_nblocksy);
249bf215546Sopenharmony_ci#endif
250bf215546Sopenharmony_ci
251bf215546Sopenharmony_ci   return true;
252bf215546Sopenharmony_ci}
253bf215546Sopenharmony_ci
254bf215546Sopenharmony_ci/**
255bf215546Sopenharmony_ci * Helper function for special layouts
256bf215546Sopenharmony_ci */
257bf215546Sopenharmony_cistatic bool
258bf215546Sopenharmony_cii9x5_special_layout(struct i915_texture *tex)
259bf215546Sopenharmony_ci{
260bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
261bf215546Sopenharmony_ci
262bf215546Sopenharmony_ci   /* Scanouts needs special care */
263bf215546Sopenharmony_ci   if (pt->bind & PIPE_BIND_SCANOUT)
264bf215546Sopenharmony_ci      if (i9x5_scanout_layout(tex))
265bf215546Sopenharmony_ci         return true;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   /* Shared buffers needs to be compatible with X servers
268bf215546Sopenharmony_ci    *
269bf215546Sopenharmony_ci    * XXX: need a better name than shared for this if it is to be part
270bf215546Sopenharmony_ci    * of core gallium, and probably move the flag to resource.flags,
271bf215546Sopenharmony_ci    * rather than bindings.
272bf215546Sopenharmony_ci    */
273bf215546Sopenharmony_ci   if (pt->bind & (PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET))
274bf215546Sopenharmony_ci      if (i9x5_display_target_layout(tex))
275bf215546Sopenharmony_ci         return true;
276bf215546Sopenharmony_ci
277bf215546Sopenharmony_ci   return false;
278bf215546Sopenharmony_ci}
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci/**
281bf215546Sopenharmony_ci * Cube layout used on i915 and for non-compressed textures on i945.
282bf215546Sopenharmony_ci *
283bf215546Sopenharmony_ci * Hardware layout looks like:
284bf215546Sopenharmony_ci *
285bf215546Sopenharmony_ci * +-------+-------+
286bf215546Sopenharmony_ci * |       |       |
287bf215546Sopenharmony_ci * |       |       |
288bf215546Sopenharmony_ci * |       |       |
289bf215546Sopenharmony_ci * |  +x   |  +y   |
290bf215546Sopenharmony_ci * |       |       |
291bf215546Sopenharmony_ci * |       |       |
292bf215546Sopenharmony_ci * |       |       |
293bf215546Sopenharmony_ci * |       |       |
294bf215546Sopenharmony_ci * +---+---+-------+
295bf215546Sopenharmony_ci * |   |   |       |
296bf215546Sopenharmony_ci * | +x| +y|       |
297bf215546Sopenharmony_ci * |   |   |       |
298bf215546Sopenharmony_ci * |   |   |       |
299bf215546Sopenharmony_ci * +-+-+---+  +z   |
300bf215546Sopenharmony_ci * | | |   |       |
301bf215546Sopenharmony_ci * +-+-+ +z|       |
302bf215546Sopenharmony_ci *   | |   |       |
303bf215546Sopenharmony_ci * +-+-+---+-------+
304bf215546Sopenharmony_ci * |       |       |
305bf215546Sopenharmony_ci * |       |       |
306bf215546Sopenharmony_ci * |       |       |
307bf215546Sopenharmony_ci * |  -x   |  -y   |
308bf215546Sopenharmony_ci * |       |       |
309bf215546Sopenharmony_ci * |       |       |
310bf215546Sopenharmony_ci * |       |       |
311bf215546Sopenharmony_ci * |       |       |
312bf215546Sopenharmony_ci * +---+---+-------+
313bf215546Sopenharmony_ci * |   |   |       |
314bf215546Sopenharmony_ci * | -x| -y|       |
315bf215546Sopenharmony_ci * |   |   |       |
316bf215546Sopenharmony_ci * |   |   |       |
317bf215546Sopenharmony_ci * +-+-+---+  -z   |
318bf215546Sopenharmony_ci * | | |   |       |
319bf215546Sopenharmony_ci * +-+-+ -z|       |
320bf215546Sopenharmony_ci *   | |   |       |
321bf215546Sopenharmony_ci *   +-+---+-------+
322bf215546Sopenharmony_ci *
323bf215546Sopenharmony_ci */
324bf215546Sopenharmony_cistatic void
325bf215546Sopenharmony_cii9x5_texture_layout_cube(struct i915_texture *tex)
326bf215546Sopenharmony_ci{
327bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
328bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
329bf215546Sopenharmony_ci   const unsigned nblocks = util_format_get_nblocksx(pt->format, width);
330bf215546Sopenharmony_ci   unsigned level;
331bf215546Sopenharmony_ci   unsigned face;
332bf215546Sopenharmony_ci
333bf215546Sopenharmony_ci   assert(pt->width0 == pt->height0); /* cubemap images are square */
334bf215546Sopenharmony_ci
335bf215546Sopenharmony_ci   /* double pitch for cube layouts */
336bf215546Sopenharmony_ci   tex->stride = align(nblocks * util_format_get_blocksize(pt->format) * 2, 4);
337bf215546Sopenharmony_ci   tex->total_nblocksy = nblocks * 4;
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++)
340bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, 6);
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci   for (face = 0; face < 6; face++) {
343bf215546Sopenharmony_ci      unsigned x = initial_offsets[face][0] * nblocks;
344bf215546Sopenharmony_ci      unsigned y = initial_offsets[face][1] * nblocks;
345bf215546Sopenharmony_ci      unsigned d = nblocks;
346bf215546Sopenharmony_ci
347bf215546Sopenharmony_ci      for (level = 0; level <= pt->last_level; level++) {
348bf215546Sopenharmony_ci         i915_texture_set_image_offset(tex, level, face, x, y);
349bf215546Sopenharmony_ci         d >>= 1;
350bf215546Sopenharmony_ci         x += step_offsets[face][0] * d;
351bf215546Sopenharmony_ci         y += step_offsets[face][1] * d;
352bf215546Sopenharmony_ci      }
353bf215546Sopenharmony_ci   }
354bf215546Sopenharmony_ci}
355bf215546Sopenharmony_ci
356bf215546Sopenharmony_ci/*
357bf215546Sopenharmony_ci * i915 layout functions
358bf215546Sopenharmony_ci */
359bf215546Sopenharmony_ci
360bf215546Sopenharmony_cistatic void
361bf215546Sopenharmony_cii915_texture_layout_2d(struct i915_texture *tex)
362bf215546Sopenharmony_ci{
363bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
364bf215546Sopenharmony_ci   unsigned level;
365bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
366bf215546Sopenharmony_ci   unsigned height = util_next_power_of_two(pt->height0);
367bf215546Sopenharmony_ci   unsigned nblocksy = util_format_get_nblocksy(pt->format, width);
368bf215546Sopenharmony_ci   unsigned align_y = 2;
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci   if (util_format_is_compressed(pt->format))
371bf215546Sopenharmony_ci      align_y = 1;
372bf215546Sopenharmony_ci
373bf215546Sopenharmony_ci   tex->stride = align(util_format_get_stride(pt->format, width), 4);
374bf215546Sopenharmony_ci   tex->total_nblocksy = 0;
375bf215546Sopenharmony_ci
376bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++) {
377bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, 1);
378bf215546Sopenharmony_ci      i915_texture_set_image_offset(tex, level, 0, 0, tex->total_nblocksy);
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci      tex->total_nblocksy += nblocksy;
381bf215546Sopenharmony_ci
382bf215546Sopenharmony_ci      width = u_minify(width, 1);
383bf215546Sopenharmony_ci      height = u_minify(height, 1);
384bf215546Sopenharmony_ci      nblocksy = align_nblocksy(pt->format, height, align_y);
385bf215546Sopenharmony_ci   }
386bf215546Sopenharmony_ci}
387bf215546Sopenharmony_ci
388bf215546Sopenharmony_cistatic void
389bf215546Sopenharmony_cii915_texture_layout_3d(struct i915_texture *tex)
390bf215546Sopenharmony_ci{
391bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
392bf215546Sopenharmony_ci   unsigned level;
393bf215546Sopenharmony_ci
394bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
395bf215546Sopenharmony_ci   unsigned height = util_next_power_of_two(pt->height0);
396bf215546Sopenharmony_ci   unsigned depth = util_next_power_of_two(pt->depth0);
397bf215546Sopenharmony_ci   unsigned nblocksy = util_format_get_nblocksy(pt->format, height);
398bf215546Sopenharmony_ci   unsigned stack_nblocksy = 0;
399bf215546Sopenharmony_ci
400bf215546Sopenharmony_ci   /* Calculate the size of a single slice.
401bf215546Sopenharmony_ci    */
402bf215546Sopenharmony_ci   tex->stride = align(util_format_get_stride(pt->format, width), 4);
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci   /* XXX: hardware expects/requires 9 levels at minimum.
405bf215546Sopenharmony_ci    */
406bf215546Sopenharmony_ci   for (level = 0; level <= MAX2(8, pt->last_level); level++) {
407bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, depth);
408bf215546Sopenharmony_ci
409bf215546Sopenharmony_ci      stack_nblocksy += MAX2(2, nblocksy);
410bf215546Sopenharmony_ci
411bf215546Sopenharmony_ci      width = u_minify(width, 1);
412bf215546Sopenharmony_ci      height = u_minify(height, 1);
413bf215546Sopenharmony_ci      nblocksy = util_format_get_nblocksy(pt->format, height);
414bf215546Sopenharmony_ci   }
415bf215546Sopenharmony_ci
416bf215546Sopenharmony_ci   /* Fixup depth image_offsets:
417bf215546Sopenharmony_ci    */
418bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++) {
419bf215546Sopenharmony_ci      unsigned i;
420bf215546Sopenharmony_ci      for (i = 0; i < depth; i++)
421bf215546Sopenharmony_ci         i915_texture_set_image_offset(tex, level, i, 0, i * stack_nblocksy);
422bf215546Sopenharmony_ci
423bf215546Sopenharmony_ci      depth = u_minify(depth, 1);
424bf215546Sopenharmony_ci   }
425bf215546Sopenharmony_ci
426bf215546Sopenharmony_ci   /* Multiply slice size by texture depth for total size.  It's
427bf215546Sopenharmony_ci    * remarkable how wasteful of memory the i915 texture layouts
428bf215546Sopenharmony_ci    * are.  They are largely fixed in the i945.
429bf215546Sopenharmony_ci    */
430bf215546Sopenharmony_ci   tex->total_nblocksy = stack_nblocksy * util_next_power_of_two(pt->depth0);
431bf215546Sopenharmony_ci}
432bf215546Sopenharmony_ci
433bf215546Sopenharmony_cistatic bool
434bf215546Sopenharmony_cii915_texture_layout(struct i915_texture *tex)
435bf215546Sopenharmony_ci{
436bf215546Sopenharmony_ci   switch (tex->b.target) {
437bf215546Sopenharmony_ci   case PIPE_TEXTURE_1D:
438bf215546Sopenharmony_ci   case PIPE_TEXTURE_2D:
439bf215546Sopenharmony_ci   case PIPE_TEXTURE_RECT:
440bf215546Sopenharmony_ci      if (!i9x5_special_layout(tex))
441bf215546Sopenharmony_ci         i915_texture_layout_2d(tex);
442bf215546Sopenharmony_ci      break;
443bf215546Sopenharmony_ci   case PIPE_TEXTURE_3D:
444bf215546Sopenharmony_ci      i915_texture_layout_3d(tex);
445bf215546Sopenharmony_ci      break;
446bf215546Sopenharmony_ci   case PIPE_TEXTURE_CUBE:
447bf215546Sopenharmony_ci      i9x5_texture_layout_cube(tex);
448bf215546Sopenharmony_ci      break;
449bf215546Sopenharmony_ci   default:
450bf215546Sopenharmony_ci      assert(0);
451bf215546Sopenharmony_ci      return false;
452bf215546Sopenharmony_ci   }
453bf215546Sopenharmony_ci
454bf215546Sopenharmony_ci   return true;
455bf215546Sopenharmony_ci}
456bf215546Sopenharmony_ci
457bf215546Sopenharmony_ci/*
458bf215546Sopenharmony_ci * i945 layout functions
459bf215546Sopenharmony_ci */
460bf215546Sopenharmony_ci
461bf215546Sopenharmony_cistatic void
462bf215546Sopenharmony_cii945_texture_layout_2d(struct i915_texture *tex)
463bf215546Sopenharmony_ci{
464bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
465bf215546Sopenharmony_ci   int align_x = 4, align_y = 2;
466bf215546Sopenharmony_ci   unsigned level;
467bf215546Sopenharmony_ci   unsigned x = 0;
468bf215546Sopenharmony_ci   unsigned y = 0;
469bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
470bf215546Sopenharmony_ci   unsigned height = util_next_power_of_two(pt->height0);
471bf215546Sopenharmony_ci   unsigned nblocksx = util_format_get_nblocksx(pt->format, width);
472bf215546Sopenharmony_ci   unsigned nblocksy = util_format_get_nblocksy(pt->format, height);
473bf215546Sopenharmony_ci
474bf215546Sopenharmony_ci   if (util_format_is_compressed(pt->format)) {
475bf215546Sopenharmony_ci      align_x = 1;
476bf215546Sopenharmony_ci      align_y = 1;
477bf215546Sopenharmony_ci   }
478bf215546Sopenharmony_ci
479bf215546Sopenharmony_ci   tex->stride = align(util_format_get_stride(pt->format, width), 4);
480bf215546Sopenharmony_ci
481bf215546Sopenharmony_ci   /* May need to adjust pitch to accommodate the placement of
482bf215546Sopenharmony_ci    * the 2nd mipmap level.  This occurs when the alignment
483bf215546Sopenharmony_ci    * constraints of mipmap placement push the right edge of the
484bf215546Sopenharmony_ci    * 2nd mipmap level out past the width of its parent.
485bf215546Sopenharmony_ci    */
486bf215546Sopenharmony_ci   if (pt->last_level > 0) {
487bf215546Sopenharmony_ci      unsigned mip1_nblocksx =
488bf215546Sopenharmony_ci         align_nblocksx(pt->format, u_minify(width, 1), align_x) +
489bf215546Sopenharmony_ci         util_format_get_nblocksx(pt->format, u_minify(width, 2));
490bf215546Sopenharmony_ci
491bf215546Sopenharmony_ci      if (mip1_nblocksx > nblocksx)
492bf215546Sopenharmony_ci         tex->stride = mip1_nblocksx * util_format_get_blocksize(pt->format);
493bf215546Sopenharmony_ci   }
494bf215546Sopenharmony_ci
495bf215546Sopenharmony_ci   /* Pitch must be a whole number of dwords
496bf215546Sopenharmony_ci    */
497bf215546Sopenharmony_ci   tex->stride = align(tex->stride, 64);
498bf215546Sopenharmony_ci   tex->total_nblocksy = 0;
499bf215546Sopenharmony_ci
500bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++) {
501bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, 1);
502bf215546Sopenharmony_ci      i915_texture_set_image_offset(tex, level, 0, x, y);
503bf215546Sopenharmony_ci
504bf215546Sopenharmony_ci      /* Because the images are packed better, the final offset
505bf215546Sopenharmony_ci       * might not be the maximal one:
506bf215546Sopenharmony_ci       */
507bf215546Sopenharmony_ci      tex->total_nblocksy = MAX2(tex->total_nblocksy, y + nblocksy);
508bf215546Sopenharmony_ci
509bf215546Sopenharmony_ci      /* Layout_below: step right after second mipmap level.
510bf215546Sopenharmony_ci       */
511bf215546Sopenharmony_ci      if (level == 1) {
512bf215546Sopenharmony_ci         x += nblocksx;
513bf215546Sopenharmony_ci      } else {
514bf215546Sopenharmony_ci         y += nblocksy;
515bf215546Sopenharmony_ci      }
516bf215546Sopenharmony_ci
517bf215546Sopenharmony_ci      width = u_minify(width, 1);
518bf215546Sopenharmony_ci      height = u_minify(height, 1);
519bf215546Sopenharmony_ci      nblocksx = align_nblocksx(pt->format, width, align_x);
520bf215546Sopenharmony_ci      nblocksy = align_nblocksy(pt->format, height, align_y);
521bf215546Sopenharmony_ci   }
522bf215546Sopenharmony_ci}
523bf215546Sopenharmony_ci
524bf215546Sopenharmony_cistatic void
525bf215546Sopenharmony_cii945_texture_layout_3d(struct i915_texture *tex)
526bf215546Sopenharmony_ci{
527bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
528bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
529bf215546Sopenharmony_ci   unsigned height = util_next_power_of_two(pt->height0);
530bf215546Sopenharmony_ci   unsigned depth = util_next_power_of_two(pt->depth0);
531bf215546Sopenharmony_ci   unsigned nblocksy = util_format_get_nblocksy(pt->format, height);
532bf215546Sopenharmony_ci   unsigned pack_x_pitch, pack_x_nr;
533bf215546Sopenharmony_ci   unsigned pack_y_pitch;
534bf215546Sopenharmony_ci   unsigned level;
535bf215546Sopenharmony_ci
536bf215546Sopenharmony_ci   tex->stride = align(util_format_get_stride(pt->format, width), 4);
537bf215546Sopenharmony_ci   tex->total_nblocksy = 0;
538bf215546Sopenharmony_ci
539bf215546Sopenharmony_ci   pack_y_pitch = MAX2(nblocksy, 2);
540bf215546Sopenharmony_ci   pack_x_pitch = tex->stride / util_format_get_blocksize(pt->format);
541bf215546Sopenharmony_ci   pack_x_nr = 1;
542bf215546Sopenharmony_ci
543bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++) {
544bf215546Sopenharmony_ci      int x = 0;
545bf215546Sopenharmony_ci      int y = 0;
546bf215546Sopenharmony_ci      unsigned q, j;
547bf215546Sopenharmony_ci
548bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, depth);
549bf215546Sopenharmony_ci
550bf215546Sopenharmony_ci      for (q = 0; q < depth;) {
551bf215546Sopenharmony_ci         for (j = 0; j < pack_x_nr && q < depth; j++, q++) {
552bf215546Sopenharmony_ci            i915_texture_set_image_offset(tex, level, q, x,
553bf215546Sopenharmony_ci                                          y + tex->total_nblocksy);
554bf215546Sopenharmony_ci            x += pack_x_pitch;
555bf215546Sopenharmony_ci         }
556bf215546Sopenharmony_ci
557bf215546Sopenharmony_ci         x = 0;
558bf215546Sopenharmony_ci         y += pack_y_pitch;
559bf215546Sopenharmony_ci      }
560bf215546Sopenharmony_ci
561bf215546Sopenharmony_ci      tex->total_nblocksy += y;
562bf215546Sopenharmony_ci
563bf215546Sopenharmony_ci      if (pack_x_pitch > 4) {
564bf215546Sopenharmony_ci         pack_x_pitch >>= 1;
565bf215546Sopenharmony_ci         pack_x_nr <<= 1;
566bf215546Sopenharmony_ci         assert(pack_x_pitch * pack_x_nr *
567bf215546Sopenharmony_ci                   util_format_get_blocksize(pt->format) <=
568bf215546Sopenharmony_ci                tex->stride);
569bf215546Sopenharmony_ci      }
570bf215546Sopenharmony_ci
571bf215546Sopenharmony_ci      if (pack_y_pitch > 2) {
572bf215546Sopenharmony_ci         pack_y_pitch >>= 1;
573bf215546Sopenharmony_ci      }
574bf215546Sopenharmony_ci
575bf215546Sopenharmony_ci      width = u_minify(width, 1);
576bf215546Sopenharmony_ci      height = u_minify(height, 1);
577bf215546Sopenharmony_ci      depth = u_minify(depth, 1);
578bf215546Sopenharmony_ci      nblocksy = util_format_get_nblocksy(pt->format, height);
579bf215546Sopenharmony_ci   }
580bf215546Sopenharmony_ci}
581bf215546Sopenharmony_ci
582bf215546Sopenharmony_ci/**
583bf215546Sopenharmony_ci * Compressed cube texture map layout for i945 and later.
584bf215546Sopenharmony_ci *
585bf215546Sopenharmony_ci * The hardware layout looks like the 830-915 layout, except for the small
586bf215546Sopenharmony_ci * sizes.  A zoomed in view of the layout for 945 is:
587bf215546Sopenharmony_ci *
588bf215546Sopenharmony_ci * +-------+-------+
589bf215546Sopenharmony_ci * |  8x8  |  8x8  |
590bf215546Sopenharmony_ci * |       |       |
591bf215546Sopenharmony_ci * |       |       |
592bf215546Sopenharmony_ci * |  +x   |  +y   |
593bf215546Sopenharmony_ci * |       |       |
594bf215546Sopenharmony_ci * |       |       |
595bf215546Sopenharmony_ci * |       |       |
596bf215546Sopenharmony_ci * |       |       |
597bf215546Sopenharmony_ci * +---+---+-------+
598bf215546Sopenharmony_ci * |4x4|   |  8x8  |
599bf215546Sopenharmony_ci * | +x|   |       |
600bf215546Sopenharmony_ci * |   |   |       |
601bf215546Sopenharmony_ci * |   |   |       |
602bf215546Sopenharmony_ci * +---+   |  +z   |
603bf215546Sopenharmony_ci * |4x4|   |       |
604bf215546Sopenharmony_ci * | +y|   |       |
605bf215546Sopenharmony_ci * |   |   |       |
606bf215546Sopenharmony_ci * +---+   +-------+
607bf215546Sopenharmony_ci *
608bf215546Sopenharmony_ci * ...
609bf215546Sopenharmony_ci *
610bf215546Sopenharmony_ci * +-------+-------+
611bf215546Sopenharmony_ci * |  8x8  |  8x8  |
612bf215546Sopenharmony_ci * |       |       |
613bf215546Sopenharmony_ci * |       |       |
614bf215546Sopenharmony_ci * |  -x   |  -y   |
615bf215546Sopenharmony_ci * |       |       |
616bf215546Sopenharmony_ci * |       |       |
617bf215546Sopenharmony_ci * |       |       |
618bf215546Sopenharmony_ci * |       |       |
619bf215546Sopenharmony_ci * +---+---+-------+
620bf215546Sopenharmony_ci * |4x4|   |  8x8  |
621bf215546Sopenharmony_ci * | -x|   |       |
622bf215546Sopenharmony_ci * |   |   |       |
623bf215546Sopenharmony_ci * |   |   |       |
624bf215546Sopenharmony_ci * +---+   |  -z   |
625bf215546Sopenharmony_ci * |4x4|   |       |
626bf215546Sopenharmony_ci * | -y|   |       |
627bf215546Sopenharmony_ci * |   |   |       |
628bf215546Sopenharmony_ci * +---+   +---+---+---+---+---+---+---+---+---+
629bf215546Sopenharmony_ci * |4x4|   |4x4|   |2x2|   |2x2|   |2x2|   |2x2|
630bf215546Sopenharmony_ci * | +z|   | -z|   | +x|   | +y|   | +z|   | -x| ...
631bf215546Sopenharmony_ci * |   |   |   |   |   |   |   |   |   |   |   |
632bf215546Sopenharmony_ci * +---+   +---+   +---+   +---+   +---+   +---+
633bf215546Sopenharmony_ci *
634bf215546Sopenharmony_ci * The bottom row continues with the remaining 2x2 then the 1x1 mip contents
635bf215546Sopenharmony_ci * in order, with each of them aligned to a 8x8 block boundary.  Thus, for
636bf215546Sopenharmony_ci * 32x32 cube maps and smaller, the bottom row layout is going to dictate the
637bf215546Sopenharmony_ci * pitch of the tree.  For a tree with 4x4 images, the pitch is at least
638bf215546Sopenharmony_ci * 14 * 8 = 112 texels, for 2x2 it is at least 12 * 8 texels, and for 1x1
639bf215546Sopenharmony_ci * it is 6 * 8 texels.
640bf215546Sopenharmony_ci */
641bf215546Sopenharmony_cistatic void
642bf215546Sopenharmony_cii945_texture_layout_cube(struct i915_texture *tex)
643bf215546Sopenharmony_ci{
644bf215546Sopenharmony_ci   struct pipe_resource *pt = &tex->b;
645bf215546Sopenharmony_ci   unsigned width = util_next_power_of_two(pt->width0);
646bf215546Sopenharmony_ci   const unsigned nblocks = util_format_get_nblocksx(pt->format, width);
647bf215546Sopenharmony_ci   const unsigned dim = width;
648bf215546Sopenharmony_ci   unsigned level;
649bf215546Sopenharmony_ci   unsigned face;
650bf215546Sopenharmony_ci
651bf215546Sopenharmony_ci   assert(pt->width0 == pt->height0); /* cubemap images are square */
652bf215546Sopenharmony_ci   assert(util_format_is_compressed(pt->format)); /* compressed only */
653bf215546Sopenharmony_ci
654bf215546Sopenharmony_ci   /*
655bf215546Sopenharmony_ci    * Depending on the size of the largest images, pitch can be
656bf215546Sopenharmony_ci    * determined either by the old-style packing of cubemap faces,
657bf215546Sopenharmony_ci    * or the final row of 4x4, 2x2 and 1x1 faces below this.
658bf215546Sopenharmony_ci    *
659bf215546Sopenharmony_ci    * 64  * 2 / 4 = 32
660bf215546Sopenharmony_ci    * 14 * 2 = 28
661bf215546Sopenharmony_ci    */
662bf215546Sopenharmony_ci   if (width >= 64)
663bf215546Sopenharmony_ci      tex->stride = nblocks * 2 * util_format_get_blocksize(pt->format);
664bf215546Sopenharmony_ci   else
665bf215546Sopenharmony_ci      tex->stride = 14 * 2 * util_format_get_blocksize(pt->format);
666bf215546Sopenharmony_ci
667bf215546Sopenharmony_ci   /*
668bf215546Sopenharmony_ci    * Something similary apply for height as well.
669bf215546Sopenharmony_ci    */
670bf215546Sopenharmony_ci   if (width >= 4)
671bf215546Sopenharmony_ci      tex->total_nblocksy = nblocks * 4 + 1;
672bf215546Sopenharmony_ci   else
673bf215546Sopenharmony_ci      tex->total_nblocksy = 1;
674bf215546Sopenharmony_ci
675bf215546Sopenharmony_ci   /* Set all the levels to effectively occupy the whole rectangular region */
676bf215546Sopenharmony_ci   for (level = 0; level <= pt->last_level; level++)
677bf215546Sopenharmony_ci      i915_texture_set_level_info(tex, level, 6);
678bf215546Sopenharmony_ci
679bf215546Sopenharmony_ci   for (face = 0; face < 6; face++) {
680bf215546Sopenharmony_ci      /* all calculations in pixels */
681bf215546Sopenharmony_ci      unsigned total_height = tex->total_nblocksy * 4;
682bf215546Sopenharmony_ci      unsigned x = initial_offsets[face][0] * dim;
683bf215546Sopenharmony_ci      unsigned y = initial_offsets[face][1] * dim;
684bf215546Sopenharmony_ci      unsigned d = dim;
685bf215546Sopenharmony_ci
686bf215546Sopenharmony_ci      if (dim == 4 && face >= 4) {
687bf215546Sopenharmony_ci         x = (face - 4) * 8;
688bf215546Sopenharmony_ci         y = tex->total_nblocksy * 4 - 4; /* 4 = 1 block */
689bf215546Sopenharmony_ci      } else if (dim < 4 && (face > 0)) {
690bf215546Sopenharmony_ci         x = face * 8;
691bf215546Sopenharmony_ci         y = total_height - 4;
692bf215546Sopenharmony_ci      }
693bf215546Sopenharmony_ci
694bf215546Sopenharmony_ci      for (level = 0; level <= pt->last_level; level++) {
695bf215546Sopenharmony_ci         i915_texture_set_image_offset(tex, level, face,
696bf215546Sopenharmony_ci                                       util_format_get_nblocksx(pt->format, x),
697bf215546Sopenharmony_ci                                       util_format_get_nblocksy(pt->format, y));
698bf215546Sopenharmony_ci
699bf215546Sopenharmony_ci         d >>= 1;
700bf215546Sopenharmony_ci
701bf215546Sopenharmony_ci         switch (d) {
702bf215546Sopenharmony_ci         case 4:
703bf215546Sopenharmony_ci            switch (face) {
704bf215546Sopenharmony_ci            case PIPE_TEX_FACE_POS_X:
705bf215546Sopenharmony_ci            case PIPE_TEX_FACE_NEG_X:
706bf215546Sopenharmony_ci               x += step_offsets[face][0] * d;
707bf215546Sopenharmony_ci               y += step_offsets[face][1] * d;
708bf215546Sopenharmony_ci               break;
709bf215546Sopenharmony_ci            case PIPE_TEX_FACE_POS_Y:
710bf215546Sopenharmony_ci            case PIPE_TEX_FACE_NEG_Y:
711bf215546Sopenharmony_ci               y += 12;
712bf215546Sopenharmony_ci               x -= 8;
713bf215546Sopenharmony_ci               break;
714bf215546Sopenharmony_ci            case PIPE_TEX_FACE_POS_Z:
715bf215546Sopenharmony_ci            case PIPE_TEX_FACE_NEG_Z:
716bf215546Sopenharmony_ci               y = total_height - 4;
717bf215546Sopenharmony_ci               x = (face - 4) * 8;
718bf215546Sopenharmony_ci               break;
719bf215546Sopenharmony_ci            }
720bf215546Sopenharmony_ci            break;
721bf215546Sopenharmony_ci         case 2:
722bf215546Sopenharmony_ci            y = total_height - 4;
723bf215546Sopenharmony_ci            x = bottom_offsets[face];
724bf215546Sopenharmony_ci            break;
725bf215546Sopenharmony_ci         case 1:
726bf215546Sopenharmony_ci            x += 48;
727bf215546Sopenharmony_ci            break;
728bf215546Sopenharmony_ci         default:
729bf215546Sopenharmony_ci            x += step_offsets[face][0] * d;
730bf215546Sopenharmony_ci            y += step_offsets[face][1] * d;
731bf215546Sopenharmony_ci            break;
732bf215546Sopenharmony_ci         }
733bf215546Sopenharmony_ci      }
734bf215546Sopenharmony_ci   }
735bf215546Sopenharmony_ci}
736bf215546Sopenharmony_ci
737bf215546Sopenharmony_cistatic bool
738bf215546Sopenharmony_cii945_texture_layout(struct i915_texture *tex)
739bf215546Sopenharmony_ci{
740bf215546Sopenharmony_ci   switch (tex->b.target) {
741bf215546Sopenharmony_ci   case PIPE_TEXTURE_1D:
742bf215546Sopenharmony_ci   case PIPE_TEXTURE_2D:
743bf215546Sopenharmony_ci   case PIPE_TEXTURE_RECT:
744bf215546Sopenharmony_ci      if (!i9x5_special_layout(tex))
745bf215546Sopenharmony_ci         i945_texture_layout_2d(tex);
746bf215546Sopenharmony_ci      break;
747bf215546Sopenharmony_ci   case PIPE_TEXTURE_3D:
748bf215546Sopenharmony_ci      i945_texture_layout_3d(tex);
749bf215546Sopenharmony_ci      break;
750bf215546Sopenharmony_ci   case PIPE_TEXTURE_CUBE:
751bf215546Sopenharmony_ci      if (!util_format_is_compressed(tex->b.format))
752bf215546Sopenharmony_ci         i9x5_texture_layout_cube(tex);
753bf215546Sopenharmony_ci      else
754bf215546Sopenharmony_ci         i945_texture_layout_cube(tex);
755bf215546Sopenharmony_ci      break;
756bf215546Sopenharmony_ci   default:
757bf215546Sopenharmony_ci      assert(0);
758bf215546Sopenharmony_ci      return false;
759bf215546Sopenharmony_ci   }
760bf215546Sopenharmony_ci
761bf215546Sopenharmony_ci   return true;
762bf215546Sopenharmony_ci}
763bf215546Sopenharmony_ci
764bf215546Sopenharmony_ci/*
765bf215546Sopenharmony_ci * Screen texture functions
766bf215546Sopenharmony_ci */
767bf215546Sopenharmony_ci
768bf215546Sopenharmony_cibool
769bf215546Sopenharmony_cii915_resource_get_handle(struct pipe_screen *screen,
770bf215546Sopenharmony_ci                         struct pipe_context *context,
771bf215546Sopenharmony_ci                         struct pipe_resource *texture,
772bf215546Sopenharmony_ci                         struct winsys_handle *whandle, unsigned usage)
773bf215546Sopenharmony_ci{
774bf215546Sopenharmony_ci   if (texture->target == PIPE_BUFFER)
775bf215546Sopenharmony_ci      return false;
776bf215546Sopenharmony_ci
777bf215546Sopenharmony_ci   struct i915_screen *is = i915_screen(screen);
778bf215546Sopenharmony_ci   struct i915_texture *tex = i915_texture(texture);
779bf215546Sopenharmony_ci   struct i915_winsys *iws = is->iws;
780bf215546Sopenharmony_ci
781bf215546Sopenharmony_ci   return iws->buffer_get_handle(iws, tex->buffer, whandle, tex->stride);
782bf215546Sopenharmony_ci}
783bf215546Sopenharmony_ci
784bf215546Sopenharmony_civoid *
785bf215546Sopenharmony_cii915_texture_transfer_map(struct pipe_context *pipe,
786bf215546Sopenharmony_ci                          struct pipe_resource *resource, unsigned level,
787bf215546Sopenharmony_ci                          unsigned usage, const struct pipe_box *box,
788bf215546Sopenharmony_ci                          struct pipe_transfer **ptransfer)
789bf215546Sopenharmony_ci{
790bf215546Sopenharmony_ci   struct i915_context *i915 = i915_context(pipe);
791bf215546Sopenharmony_ci   struct i915_texture *tex = i915_texture(resource);
792bf215546Sopenharmony_ci   struct i915_transfer *transfer = slab_alloc_st(&i915->texture_transfer_pool);
793bf215546Sopenharmony_ci   bool use_staging_texture = false;
794bf215546Sopenharmony_ci   struct i915_winsys *iws = i915_screen(pipe->screen)->iws;
795bf215546Sopenharmony_ci   enum pipe_format format = resource->format;
796bf215546Sopenharmony_ci   unsigned offset;
797bf215546Sopenharmony_ci   char *map;
798bf215546Sopenharmony_ci
799bf215546Sopenharmony_ci   if (!transfer)
800bf215546Sopenharmony_ci      return NULL;
801bf215546Sopenharmony_ci
802bf215546Sopenharmony_ci   transfer->b.resource = resource;
803bf215546Sopenharmony_ci   transfer->b.level = level;
804bf215546Sopenharmony_ci   transfer->b.usage = usage;
805bf215546Sopenharmony_ci   transfer->b.box = *box;
806bf215546Sopenharmony_ci   transfer->b.stride = tex->stride;
807bf215546Sopenharmony_ci   transfer->staging_texture = NULL;
808bf215546Sopenharmony_ci   /* XXX: handle depth textures everyhwere*/
809bf215546Sopenharmony_ci   transfer->b.layer_stride = 0;
810bf215546Sopenharmony_ci
811bf215546Sopenharmony_ci   /* if we use staging transfers, only support textures we can render to,
812bf215546Sopenharmony_ci    * because we need that for u_blitter */
813bf215546Sopenharmony_ci   if (i915->blitter &&
814bf215546Sopenharmony_ci       util_blitter_is_copy_supported(i915->blitter, resource, resource) &&
815bf215546Sopenharmony_ci       (usage & PIPE_MAP_WRITE) &&
816bf215546Sopenharmony_ci       !(usage &
817bf215546Sopenharmony_ci         (PIPE_MAP_READ | PIPE_MAP_DONTBLOCK | PIPE_MAP_UNSYNCHRONIZED)))
818bf215546Sopenharmony_ci      use_staging_texture = true;
819bf215546Sopenharmony_ci
820bf215546Sopenharmony_ci   use_staging_texture = false;
821bf215546Sopenharmony_ci
822bf215546Sopenharmony_ci   if (use_staging_texture) {
823bf215546Sopenharmony_ci      /*
824bf215546Sopenharmony_ci       * Allocate the untiled staging texture.
825bf215546Sopenharmony_ci       * If the alloc fails, transfer->staging_texture is NULL and we fallback
826bf215546Sopenharmony_ci       * to a map()
827bf215546Sopenharmony_ci       */
828bf215546Sopenharmony_ci      transfer->staging_texture =
829bf215546Sopenharmony_ci         i915_texture_create(pipe->screen, resource, true);
830bf215546Sopenharmony_ci   }
831bf215546Sopenharmony_ci
832bf215546Sopenharmony_ci   if (resource->target != PIPE_TEXTURE_3D &&
833bf215546Sopenharmony_ci       resource->target != PIPE_TEXTURE_CUBE) {
834bf215546Sopenharmony_ci      assert(box->z == 0);
835bf215546Sopenharmony_ci      assert(box->depth == 1);
836bf215546Sopenharmony_ci   }
837bf215546Sopenharmony_ci
838bf215546Sopenharmony_ci   if (transfer->staging_texture) {
839bf215546Sopenharmony_ci      tex = i915_texture(transfer->staging_texture);
840bf215546Sopenharmony_ci   } else {
841bf215546Sopenharmony_ci      /* TODO this is a sledgehammer */
842bf215546Sopenharmony_ci      tex = i915_texture(resource);
843bf215546Sopenharmony_ci      pipe->flush(pipe, NULL, 0);
844bf215546Sopenharmony_ci   }
845bf215546Sopenharmony_ci
846bf215546Sopenharmony_ci   offset = i915_texture_offset(tex, transfer->b.level, box->z);
847bf215546Sopenharmony_ci
848bf215546Sopenharmony_ci   map = iws->buffer_map(iws, tex->buffer,
849bf215546Sopenharmony_ci                         (transfer->b.usage & PIPE_MAP_WRITE) ? true : false);
850bf215546Sopenharmony_ci   if (!map) {
851bf215546Sopenharmony_ci      pipe_resource_reference(&transfer->staging_texture, NULL);
852bf215546Sopenharmony_ci      FREE(transfer);
853bf215546Sopenharmony_ci      return NULL;
854bf215546Sopenharmony_ci   }
855bf215546Sopenharmony_ci
856bf215546Sopenharmony_ci   *ptransfer = &transfer->b;
857bf215546Sopenharmony_ci
858bf215546Sopenharmony_ci   return map + offset +
859bf215546Sopenharmony_ci          box->y / util_format_get_blockheight(format) * transfer->b.stride +
860bf215546Sopenharmony_ci          box->x / util_format_get_blockwidth(format) *
861bf215546Sopenharmony_ci             util_format_get_blocksize(format);
862bf215546Sopenharmony_ci}
863bf215546Sopenharmony_ci
864bf215546Sopenharmony_civoid
865bf215546Sopenharmony_cii915_texture_transfer_unmap(struct pipe_context *pipe,
866bf215546Sopenharmony_ci                            struct pipe_transfer *transfer)
867bf215546Sopenharmony_ci{
868bf215546Sopenharmony_ci   struct i915_context *i915 = i915_context(pipe);
869bf215546Sopenharmony_ci   struct i915_transfer *itransfer = (struct i915_transfer *)transfer;
870bf215546Sopenharmony_ci   struct i915_texture *tex = i915_texture(itransfer->b.resource);
871bf215546Sopenharmony_ci   struct i915_winsys *iws = i915_screen(tex->b.screen)->iws;
872bf215546Sopenharmony_ci
873bf215546Sopenharmony_ci   if (itransfer->staging_texture)
874bf215546Sopenharmony_ci      tex = i915_texture(itransfer->staging_texture);
875bf215546Sopenharmony_ci
876bf215546Sopenharmony_ci   iws->buffer_unmap(iws, tex->buffer);
877bf215546Sopenharmony_ci
878bf215546Sopenharmony_ci   if ((itransfer->staging_texture) && (transfer->usage & PIPE_MAP_WRITE)) {
879bf215546Sopenharmony_ci      struct pipe_box sbox;
880bf215546Sopenharmony_ci
881bf215546Sopenharmony_ci      u_box_origin_2d(itransfer->b.box.width, itransfer->b.box.height, &sbox);
882bf215546Sopenharmony_ci      pipe->resource_copy_region(pipe, itransfer->b.resource,
883bf215546Sopenharmony_ci                                 itransfer->b.level, itransfer->b.box.x,
884bf215546Sopenharmony_ci                                 itransfer->b.box.y, itransfer->b.box.z,
885bf215546Sopenharmony_ci                                 itransfer->staging_texture, 0, &sbox);
886bf215546Sopenharmony_ci      pipe->flush(pipe, NULL, 0);
887bf215546Sopenharmony_ci      pipe_resource_reference(&itransfer->staging_texture, NULL);
888bf215546Sopenharmony_ci   }
889bf215546Sopenharmony_ci
890bf215546Sopenharmony_ci   slab_free_st(&i915->texture_transfer_pool, itransfer);
891bf215546Sopenharmony_ci}
892bf215546Sopenharmony_ci
893bf215546Sopenharmony_civoid
894bf215546Sopenharmony_cii915_texture_subdata(struct pipe_context *pipe, struct pipe_resource *resource,
895bf215546Sopenharmony_ci                     unsigned level, unsigned usage, const struct pipe_box *box,
896bf215546Sopenharmony_ci                     const void *data, unsigned stride, unsigned layer_stride)
897bf215546Sopenharmony_ci{
898bf215546Sopenharmony_ci   /* i915's cube and 3D maps are not laid out such that one could use a
899bf215546Sopenharmony_ci    * layer_stride to get from one layer to the next, so we have to walk the
900bf215546Sopenharmony_ci    * layers individually.
901bf215546Sopenharmony_ci    */
902bf215546Sopenharmony_ci   struct pipe_box layer_box = *box;
903bf215546Sopenharmony_ci   layer_box.depth = 1;
904bf215546Sopenharmony_ci   for (layer_box.z = box->z; layer_box.z < box->z + box->depth;
905bf215546Sopenharmony_ci        layer_box.z++) {
906bf215546Sopenharmony_ci      u_default_texture_subdata(pipe, resource, level, usage, &layer_box, data,
907bf215546Sopenharmony_ci                                stride, layer_stride);
908bf215546Sopenharmony_ci      data += layer_stride;
909bf215546Sopenharmony_ci   }
910bf215546Sopenharmony_ci}
911bf215546Sopenharmony_ci
912bf215546Sopenharmony_cistruct pipe_resource *
913bf215546Sopenharmony_cii915_texture_create(struct pipe_screen *screen,
914bf215546Sopenharmony_ci                    const struct pipe_resource *template, bool force_untiled)
915bf215546Sopenharmony_ci{
916bf215546Sopenharmony_ci   struct i915_screen *is = i915_screen(screen);
917bf215546Sopenharmony_ci   struct i915_winsys *iws = is->iws;
918bf215546Sopenharmony_ci   struct i915_texture *tex = CALLOC_STRUCT(i915_texture);
919bf215546Sopenharmony_ci   unsigned buf_usage = 0;
920bf215546Sopenharmony_ci
921bf215546Sopenharmony_ci   if (!tex)
922bf215546Sopenharmony_ci      return NULL;
923bf215546Sopenharmony_ci
924bf215546Sopenharmony_ci   tex->b = *template;
925bf215546Sopenharmony_ci   pipe_reference_init(&tex->b.reference, 1);
926bf215546Sopenharmony_ci   tex->b.screen = screen;
927bf215546Sopenharmony_ci
928bf215546Sopenharmony_ci   if ((force_untiled) || (template->usage == PIPE_USAGE_STREAM))
929bf215546Sopenharmony_ci      tex->tiling = I915_TILE_NONE;
930bf215546Sopenharmony_ci   else
931bf215546Sopenharmony_ci      tex->tiling = i915_texture_tiling(is, tex);
932bf215546Sopenharmony_ci
933bf215546Sopenharmony_ci   if (is->is_i945) {
934bf215546Sopenharmony_ci      if (!i945_texture_layout(tex))
935bf215546Sopenharmony_ci         goto fail;
936bf215546Sopenharmony_ci   } else {
937bf215546Sopenharmony_ci      if (!i915_texture_layout(tex))
938bf215546Sopenharmony_ci         goto fail;
939bf215546Sopenharmony_ci   }
940bf215546Sopenharmony_ci
941bf215546Sopenharmony_ci   /* for scanouts and cursors, cursors arn't scanouts */
942bf215546Sopenharmony_ci
943bf215546Sopenharmony_ci   /* XXX: use a custom flag for cursors, don't rely on magically
944bf215546Sopenharmony_ci    * guessing that this is Xorg asking for a cursor
945bf215546Sopenharmony_ci    */
946bf215546Sopenharmony_ci   if ((template->bind & PIPE_BIND_SCANOUT) && template->width0 != 64)
947bf215546Sopenharmony_ci      buf_usage = I915_NEW_SCANOUT;
948bf215546Sopenharmony_ci   else
949bf215546Sopenharmony_ci      buf_usage = I915_NEW_TEXTURE;
950bf215546Sopenharmony_ci
951bf215546Sopenharmony_ci   tex->buffer = iws->buffer_create_tiled(
952bf215546Sopenharmony_ci      iws, &tex->stride, tex->total_nblocksy, &tex->tiling, buf_usage);
953bf215546Sopenharmony_ci   if (!tex->buffer)
954bf215546Sopenharmony_ci      goto fail;
955bf215546Sopenharmony_ci
956bf215546Sopenharmony_ci   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n",
957bf215546Sopenharmony_ci            __func__, tex, tex->stride,
958bf215546Sopenharmony_ci            tex->stride / util_format_get_blocksize(tex->b.format),
959bf215546Sopenharmony_ci            tex->total_nblocksy, get_tiling_string(tex->tiling));
960bf215546Sopenharmony_ci
961bf215546Sopenharmony_ci   return &tex->b;
962bf215546Sopenharmony_ci
963bf215546Sopenharmony_cifail:
964bf215546Sopenharmony_ci   FREE(tex);
965bf215546Sopenharmony_ci   return NULL;
966bf215546Sopenharmony_ci}
967bf215546Sopenharmony_ci
968bf215546Sopenharmony_cistruct pipe_resource *
969bf215546Sopenharmony_cii915_texture_from_handle(struct pipe_screen *screen,
970bf215546Sopenharmony_ci                         const struct pipe_resource *template,
971bf215546Sopenharmony_ci                         struct winsys_handle *whandle)
972bf215546Sopenharmony_ci{
973bf215546Sopenharmony_ci   struct i915_screen *is = i915_screen(screen);
974bf215546Sopenharmony_ci   struct i915_texture *tex;
975bf215546Sopenharmony_ci   struct i915_winsys *iws = is->iws;
976bf215546Sopenharmony_ci   struct i915_winsys_buffer *buffer;
977bf215546Sopenharmony_ci   unsigned stride;
978bf215546Sopenharmony_ci   enum i915_winsys_buffer_tile tiling;
979bf215546Sopenharmony_ci
980bf215546Sopenharmony_ci   assert(screen);
981bf215546Sopenharmony_ci
982bf215546Sopenharmony_ci   buffer = iws->buffer_from_handle(iws, whandle, template->height0, &tiling,
983bf215546Sopenharmony_ci                                    &stride);
984bf215546Sopenharmony_ci
985bf215546Sopenharmony_ci   /* Only supports one type */
986bf215546Sopenharmony_ci   if ((template->target != PIPE_TEXTURE_2D &&
987bf215546Sopenharmony_ci        template->target != PIPE_TEXTURE_RECT) ||
988bf215546Sopenharmony_ci       template->last_level != 0 || template->depth0 != 1) {
989bf215546Sopenharmony_ci      return NULL;
990bf215546Sopenharmony_ci   }
991bf215546Sopenharmony_ci
992bf215546Sopenharmony_ci   tex = CALLOC_STRUCT(i915_texture);
993bf215546Sopenharmony_ci   if (!tex)
994bf215546Sopenharmony_ci      return NULL;
995bf215546Sopenharmony_ci
996bf215546Sopenharmony_ci   tex->b = *template;
997bf215546Sopenharmony_ci   pipe_reference_init(&tex->b.reference, 1);
998bf215546Sopenharmony_ci   tex->b.screen = screen;
999bf215546Sopenharmony_ci
1000bf215546Sopenharmony_ci   tex->stride = stride;
1001bf215546Sopenharmony_ci   tex->tiling = tiling;
1002bf215546Sopenharmony_ci   tex->total_nblocksy = align_nblocksy(tex->b.format, tex->b.height0, 8);
1003bf215546Sopenharmony_ci
1004bf215546Sopenharmony_ci   i915_texture_set_level_info(tex, 0, 1);
1005bf215546Sopenharmony_ci   i915_texture_set_image_offset(tex, 0, 0, 0, 0);
1006bf215546Sopenharmony_ci
1007bf215546Sopenharmony_ci   tex->buffer = buffer;
1008bf215546Sopenharmony_ci
1009bf215546Sopenharmony_ci   I915_DBG(DBG_TEXTURE, "%s: %p stride %u, blocks (%u, %u) tiling %s\n",
1010bf215546Sopenharmony_ci            __func__, tex, tex->stride,
1011bf215546Sopenharmony_ci            tex->stride / util_format_get_blocksize(tex->b.format),
1012bf215546Sopenharmony_ci            tex->total_nblocksy, get_tiling_string(tex->tiling));
1013bf215546Sopenharmony_ci
1014bf215546Sopenharmony_ci   return &tex->b;
1015bf215546Sopenharmony_ci}
1016