1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 2011 VMware, Inc.
5848b8605Smrg *
6848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
7848b8605Smrg * copy of this software and associated documentation files (the "Software"),
8848b8605Smrg * to deal in the Software without restriction, including without limitation
9848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
11848b8605Smrg * Software is furnished to do so, subject to the following conditions:
12848b8605Smrg *
13848b8605Smrg * The above copyright notice and this permission notice shall be included
14848b8605Smrg * in all copies or substantial portions of the Software.
15848b8605Smrg *
16848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
23848b8605Smrg */
24848b8605Smrg
25848b8605Smrg/**
26848b8605Smrg * Functions for mapping/unmapping texture images.
27848b8605Smrg */
28848b8605Smrg
29848b8605Smrg
30848b8605Smrg#include "main/context.h"
31848b8605Smrg#include "main/fbobject.h"
32848b8605Smrg#include "main/teximage.h"
33848b8605Smrg#include "main/texobj.h"
34848b8605Smrg#include "swrast/swrast.h"
35848b8605Smrg#include "swrast/s_context.h"
36848b8605Smrg
37848b8605Smrg
38848b8605Smrg/**
39848b8605Smrg * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
40848b8605Smrg * Called via ctx->Driver.NewTextureImage().
41848b8605Smrg */
42848b8605Smrgstruct gl_texture_image *
43848b8605Smrg_swrast_new_texture_image( struct gl_context *ctx )
44848b8605Smrg{
45848b8605Smrg   (void) ctx;
46848b8605Smrg   return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
47848b8605Smrg}
48848b8605Smrg
49848b8605Smrg
50848b8605Smrg/**
51848b8605Smrg * Free a swrast_texture_image (a subclass of gl_texture_image).
52848b8605Smrg * Called via ctx->Driver.DeleteTextureImage().
53848b8605Smrg */
54848b8605Smrgvoid
55848b8605Smrg_swrast_delete_texture_image(struct gl_context *ctx,
56848b8605Smrg                             struct gl_texture_image *texImage)
57848b8605Smrg{
58848b8605Smrg   /* Nothing special for the subclass yet */
59848b8605Smrg   _mesa_delete_texture_image(ctx, texImage);
60848b8605Smrg}
61848b8605Smrg
62848b8605Smrgstatic unsigned int
63b8e80941Smrgtexture_slices(const struct gl_texture_image *texImage)
64848b8605Smrg{
65848b8605Smrg   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
66848b8605Smrg      return texImage->Height;
67848b8605Smrg   else
68848b8605Smrg      return texImage->Depth;
69848b8605Smrg}
70848b8605Smrg
71848b8605Smrgunsigned int
72848b8605Smrg_swrast_teximage_slice_height(struct gl_texture_image *texImage)
73848b8605Smrg{
74848b8605Smrg   /* For 1D array textures, the slices are all 1 pixel high, and Height is
75848b8605Smrg    * the number of slices.
76848b8605Smrg    */
77848b8605Smrg   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
78848b8605Smrg      return 1;
79848b8605Smrg   else
80848b8605Smrg      return texImage->Height;
81848b8605Smrg}
82848b8605Smrg
83848b8605Smrg/**
84848b8605Smrg * Called via ctx->Driver.AllocTextureImageBuffer()
85848b8605Smrg */
86848b8605SmrgGLboolean
87848b8605Smrg_swrast_alloc_texture_image_buffer(struct gl_context *ctx,
88848b8605Smrg                                   struct gl_texture_image *texImage)
89848b8605Smrg{
90848b8605Smrg   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
91848b8605Smrg   GLuint bytesPerSlice;
92848b8605Smrg   GLuint slices = texture_slices(texImage);
93848b8605Smrg   GLuint i;
94848b8605Smrg
95848b8605Smrg   if (!_swrast_init_texture_image(texImage))
96848b8605Smrg      return GL_FALSE;
97848b8605Smrg
98848b8605Smrg   bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
99848b8605Smrg                                           _swrast_teximage_slice_height(texImage), 1);
100848b8605Smrg
101848b8605Smrg   assert(!swImg->Buffer);
102848b8605Smrg   swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512);
103848b8605Smrg   if (!swImg->Buffer)
104848b8605Smrg      return GL_FALSE;
105848b8605Smrg
106848b8605Smrg   /* RowStride and ImageSlices[] describe how to address texels in 'Data' */
107848b8605Smrg   swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
108848b8605Smrg                                              texImage->Width);
109848b8605Smrg
110848b8605Smrg   for (i = 0; i < slices; i++) {
111848b8605Smrg      swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
112848b8605Smrg   }
113848b8605Smrg
114848b8605Smrg   return GL_TRUE;
115848b8605Smrg}
116848b8605Smrg
117848b8605Smrg
118848b8605Smrg/**
119848b8605Smrg * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
120848b8605Smrg * initialize the fields of swrast_texture_image without allocating the image
121848b8605Smrg * buffer or initializing RowStride or the contents of ImageSlices.
122848b8605Smrg *
123848b8605Smrg * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
124848b8605Smrg */
125848b8605SmrgGLboolean
126848b8605Smrg_swrast_init_texture_image(struct gl_texture_image *texImage)
127848b8605Smrg{
128848b8605Smrg   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
129848b8605Smrg
130848b8605Smrg   if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
131848b8605Smrg       (texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
132848b8605Smrg       (texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
133848b8605Smrg      swImg->_IsPowerOfTwo = GL_TRUE;
134848b8605Smrg   else
135848b8605Smrg      swImg->_IsPowerOfTwo = GL_FALSE;
136848b8605Smrg
137848b8605Smrg   /* Compute Width/Height/DepthScale for mipmap lod computation */
138848b8605Smrg   if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
139848b8605Smrg      /* scale = 1.0 since texture coords directly map to texels */
140848b8605Smrg      swImg->WidthScale = 1.0;
141848b8605Smrg      swImg->HeightScale = 1.0;
142848b8605Smrg      swImg->DepthScale = 1.0;
143848b8605Smrg   }
144848b8605Smrg   else {
145848b8605Smrg      swImg->WidthScale = (GLfloat) texImage->Width;
146848b8605Smrg      swImg->HeightScale = (GLfloat) texImage->Height;
147848b8605Smrg      swImg->DepthScale = (GLfloat) texImage->Depth;
148848b8605Smrg   }
149848b8605Smrg
150848b8605Smrg   assert(!swImg->ImageSlices);
151848b8605Smrg   swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
152848b8605Smrg   if (!swImg->ImageSlices)
153848b8605Smrg      return GL_FALSE;
154848b8605Smrg
155848b8605Smrg   return GL_TRUE;
156848b8605Smrg}
157848b8605Smrg
158848b8605Smrg
159848b8605Smrg/**
160848b8605Smrg * Called via ctx->Driver.FreeTextureImageBuffer()
161848b8605Smrg */
162848b8605Smrgvoid
163848b8605Smrg_swrast_free_texture_image_buffer(struct gl_context *ctx,
164848b8605Smrg                                  struct gl_texture_image *texImage)
165848b8605Smrg{
166848b8605Smrg   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
167848b8605Smrg
168848b8605Smrg   _mesa_align_free(swImage->Buffer);
169848b8605Smrg   swImage->Buffer = NULL;
170848b8605Smrg
171848b8605Smrg   free(swImage->ImageSlices);
172848b8605Smrg   swImage->ImageSlices = NULL;
173848b8605Smrg}
174848b8605Smrg
175848b8605Smrg
176848b8605Smrg/**
177848b8605Smrg * Error checking for debugging only.
178848b8605Smrg */
179848b8605Smrgstatic void
180848b8605Smrgcheck_map_teximage(const struct gl_texture_image *texImage,
181848b8605Smrg                   GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
182848b8605Smrg{
183848b8605Smrg
184848b8605Smrg   if (texImage->TexObject->Target == GL_TEXTURE_1D)
185848b8605Smrg      assert(y == 0 && h == 1);
186848b8605Smrg
187848b8605Smrg   assert(x < texImage->Width || texImage->Width == 0);
188848b8605Smrg   assert(y < texImage->Height || texImage->Height == 0);
189848b8605Smrg   assert(x + w <= texImage->Width);
190848b8605Smrg   assert(y + h <= texImage->Height);
191b8e80941Smrg   assert(slice < texture_slices(texImage));
192848b8605Smrg}
193848b8605Smrg
194848b8605Smrg/**
195848b8605Smrg * Map a 2D slice of a texture image into user space.
196848b8605Smrg * (x,y,w,h) defines a region of interest (ROI).  Reading/writing texels
197848b8605Smrg * outside of the ROI is undefined.
198848b8605Smrg *
199848b8605Smrg * \param texImage  the texture image
200848b8605Smrg * \param slice  the 3D image slice or array texture slice
201848b8605Smrg * \param x, y, w, h  region of interest
202848b8605Smrg * \param mode  bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
203848b8605Smrg * \param mapOut  returns start of mapping of region of interest
204848b8605Smrg * \param rowStrideOut  returns row stride (in bytes)
205848b8605Smrg */
206848b8605Smrgvoid
207848b8605Smrg_swrast_map_teximage(struct gl_context *ctx,
208848b8605Smrg                     struct gl_texture_image *texImage,
209848b8605Smrg                     GLuint slice,
210848b8605Smrg                     GLuint x, GLuint y, GLuint w, GLuint h,
211848b8605Smrg                     GLbitfield mode,
212848b8605Smrg                     GLubyte **mapOut,
213848b8605Smrg                     GLint *rowStrideOut)
214848b8605Smrg{
215848b8605Smrg   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
216848b8605Smrg   GLubyte *map;
217848b8605Smrg   GLint stride, texelSize;
218848b8605Smrg   GLuint bw, bh;
219848b8605Smrg
220848b8605Smrg   check_map_teximage(texImage, slice, x, y, w, h);
221848b8605Smrg
222848b8605Smrg   if (!swImage->Buffer) {
223848b8605Smrg      /* Either glTexImage was called with a NULL <pixels> argument or
224848b8605Smrg       * we ran out of memory when allocating texture memory,
225848b8605Smrg       */
226848b8605Smrg      *mapOut = NULL;
227848b8605Smrg      *rowStrideOut = 0;
228848b8605Smrg      return;
229848b8605Smrg   }
230848b8605Smrg
231848b8605Smrg   texelSize = _mesa_get_format_bytes(texImage->TexFormat);
232848b8605Smrg   stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
233848b8605Smrg   _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
234848b8605Smrg
235848b8605Smrg   assert(x % bw == 0);
236848b8605Smrg   assert(y % bh == 0);
237848b8605Smrg
238848b8605Smrg   /* This function can only be used with a swrast-allocated buffer, in which
239848b8605Smrg    * case ImageSlices is populated with pointers into Buffer.
240848b8605Smrg    */
241848b8605Smrg   assert(swImage->Buffer);
242848b8605Smrg   assert(swImage->Buffer == swImage->ImageSlices[0]);
243848b8605Smrg
244848b8605Smrg   map = swImage->ImageSlices[slice];
245848b8605Smrg
246848b8605Smrg   /* apply x/y offset to map address */
247848b8605Smrg   map += stride * (y / bh) + texelSize * (x / bw);
248848b8605Smrg
249848b8605Smrg   *mapOut = map;
250848b8605Smrg   *rowStrideOut = stride;
251848b8605Smrg}
252848b8605Smrg
253848b8605Smrgvoid
254848b8605Smrg_swrast_unmap_teximage(struct gl_context *ctx,
255848b8605Smrg                       struct gl_texture_image *texImage,
256848b8605Smrg                       GLuint slice)
257848b8605Smrg{
258848b8605Smrg   /* nop */
259848b8605Smrg}
260848b8605Smrg
261848b8605Smrg
262848b8605Smrgvoid
263848b8605Smrg_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
264848b8605Smrg{
265848b8605Smrg   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
266848b8605Smrg   GLuint face, level;
267848b8605Smrg
268848b8605Smrg   for (face = 0; face < faces; face++) {
269848b8605Smrg      for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
270848b8605Smrg         struct gl_texture_image *texImage = texObj->Image[face][level];
271848b8605Smrg         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
272848b8605Smrg         unsigned int i, slices;
273848b8605Smrg
274848b8605Smrg         if (!texImage)
275848b8605Smrg            continue;
276848b8605Smrg
277848b8605Smrg         /* In the case of a swrast-allocated texture buffer, the ImageSlices
278848b8605Smrg          * and RowStride are always available.
279848b8605Smrg          */
280848b8605Smrg         if (swImage->Buffer) {
281848b8605Smrg            assert(swImage->ImageSlices[0] == swImage->Buffer);
282848b8605Smrg            continue;
283848b8605Smrg         }
284848b8605Smrg
285848b8605Smrg         if (!swImage->ImageSlices) {
286848b8605Smrg            swImage->ImageSlices =
287848b8605Smrg               calloc(texture_slices(texImage), sizeof(void *));
288848b8605Smrg            if (!swImage->ImageSlices)
289848b8605Smrg               continue;
290848b8605Smrg         }
291848b8605Smrg
292848b8605Smrg         slices = texture_slices(texImage);
293848b8605Smrg
294848b8605Smrg         for (i = 0; i < slices; i++) {
295848b8605Smrg            GLubyte *map;
296848b8605Smrg            GLint rowStride;
297848b8605Smrg
298848b8605Smrg            if (swImage->ImageSlices[i])
299848b8605Smrg               continue;
300848b8605Smrg
301848b8605Smrg            ctx->Driver.MapTextureImage(ctx, texImage, i,
302848b8605Smrg                                        0, 0,
303848b8605Smrg                                        texImage->Width, texImage->Height,
304848b8605Smrg                                        GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
305848b8605Smrg                                        &map, &rowStride);
306848b8605Smrg
307848b8605Smrg            swImage->ImageSlices[i] = map;
308848b8605Smrg            /* A swrast-using driver has to return the same rowstride for
309848b8605Smrg             * every slice of the same texture, since we don't track them
310848b8605Smrg             * separately.
311848b8605Smrg             */
312848b8605Smrg            if (i == 0)
313848b8605Smrg               swImage->RowStride = rowStride;
314848b8605Smrg            else
315848b8605Smrg               assert(swImage->RowStride == rowStride);
316848b8605Smrg         }
317848b8605Smrg      }
318848b8605Smrg   }
319848b8605Smrg}
320848b8605Smrg
321848b8605Smrg
322848b8605Smrgvoid
323848b8605Smrg_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
324848b8605Smrg{
325848b8605Smrg   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
326848b8605Smrg   GLuint face, level;
327848b8605Smrg
328848b8605Smrg   for (face = 0; face < faces; face++) {
329848b8605Smrg      for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
330848b8605Smrg         struct gl_texture_image *texImage = texObj->Image[face][level];
331848b8605Smrg         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
332848b8605Smrg         unsigned int i, slices;
333848b8605Smrg
334848b8605Smrg         if (!texImage)
335848b8605Smrg            continue;
336848b8605Smrg
337848b8605Smrg         if (swImage->Buffer)
338848b8605Smrg            return;
339848b8605Smrg
340848b8605Smrg         if (!swImage->ImageSlices)
341848b8605Smrg            continue;
342848b8605Smrg
343848b8605Smrg         slices = texture_slices(texImage);
344848b8605Smrg
345848b8605Smrg         for (i = 0; i < slices; i++) {
346848b8605Smrg            if (swImage->ImageSlices[i]) {
347848b8605Smrg               ctx->Driver.UnmapTextureImage(ctx, texImage, i);
348848b8605Smrg               swImage->ImageSlices[i] = NULL;
349848b8605Smrg            }
350848b8605Smrg         }
351848b8605Smrg      }
352848b8605Smrg   }
353848b8605Smrg}
354848b8605Smrg
355848b8605Smrg
356848b8605Smrg/**
357848b8605Smrg * Map all textures for reading prior to software rendering.
358848b8605Smrg */
359848b8605Smrgvoid
360848b8605Smrg_swrast_map_textures(struct gl_context *ctx)
361848b8605Smrg{
362848b8605Smrg   int unit;
363848b8605Smrg
364848b8605Smrg   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
365848b8605Smrg      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
366848b8605Smrg
367848b8605Smrg      if (texObj)
368848b8605Smrg         _swrast_map_texture(ctx, texObj);
369848b8605Smrg   }
370848b8605Smrg}
371848b8605Smrg
372848b8605Smrg
373848b8605Smrg/**
374848b8605Smrg * Unmap all textures for reading prior to software rendering.
375848b8605Smrg */
376848b8605Smrgvoid
377848b8605Smrg_swrast_unmap_textures(struct gl_context *ctx)
378848b8605Smrg{
379848b8605Smrg   int unit;
380848b8605Smrg   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
381848b8605Smrg      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
382848b8605Smrg
383848b8605Smrg      if (texObj)
384848b8605Smrg         _swrast_unmap_texture(ctx, texObj);
385848b8605Smrg   }
386848b8605Smrg}
387