1af69d88dSmrg/*
2af69d88dSmrg * Mesa 3-D graphics library
3af69d88dSmrg *
4af69d88dSmrg * Copyright (C) 2011 VMware, Inc.
5af69d88dSmrg *
6af69d88dSmrg * Permission is hereby granted, free of charge, to any person obtaining a
7af69d88dSmrg * copy of this software and associated documentation files (the "Software"),
8af69d88dSmrg * to deal in the Software without restriction, including without limitation
9af69d88dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10af69d88dSmrg * and/or sell copies of the Software, and to permit persons to whom the
11af69d88dSmrg * Software is furnished to do so, subject to the following conditions:
12af69d88dSmrg *
13af69d88dSmrg * The above copyright notice and this permission notice shall be included
14af69d88dSmrg * in all copies or substantial portions of the Software.
15af69d88dSmrg *
16af69d88dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17af69d88dSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18af69d88dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
23af69d88dSmrg */
24af69d88dSmrg
25af69d88dSmrg/**
26af69d88dSmrg * Functions for mapping/unmapping texture images.
27af69d88dSmrg */
28af69d88dSmrg
29af69d88dSmrg
30af69d88dSmrg#include "main/context.h"
31af69d88dSmrg#include "main/fbobject.h"
32af69d88dSmrg#include "main/teximage.h"
33af69d88dSmrg#include "main/texobj.h"
347ec681f3Smrg#include "util/u_memory.h"
357ec681f3Smrg#include "util/u_math.h"
36af69d88dSmrg#include "swrast/swrast.h"
37af69d88dSmrg#include "swrast/s_context.h"
38af69d88dSmrg
39af69d88dSmrg
40af69d88dSmrg/**
41af69d88dSmrg * Allocate a new swrast_texture_image (a subclass of gl_texture_image).
42af69d88dSmrg * Called via ctx->Driver.NewTextureImage().
43af69d88dSmrg */
44af69d88dSmrgstruct gl_texture_image *
45af69d88dSmrg_swrast_new_texture_image( struct gl_context *ctx )
46af69d88dSmrg{
47af69d88dSmrg   (void) ctx;
48af69d88dSmrg   return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
49af69d88dSmrg}
50af69d88dSmrg
51af69d88dSmrg
52af69d88dSmrg/**
53af69d88dSmrg * Free a swrast_texture_image (a subclass of gl_texture_image).
54af69d88dSmrg * Called via ctx->Driver.DeleteTextureImage().
55af69d88dSmrg */
56af69d88dSmrgvoid
57af69d88dSmrg_swrast_delete_texture_image(struct gl_context *ctx,
58af69d88dSmrg                             struct gl_texture_image *texImage)
59af69d88dSmrg{
60af69d88dSmrg   /* Nothing special for the subclass yet */
61af69d88dSmrg   _mesa_delete_texture_image(ctx, texImage);
62af69d88dSmrg}
63af69d88dSmrg
64af69d88dSmrgstatic unsigned int
6501e04c3fSmrgtexture_slices(const struct gl_texture_image *texImage)
66af69d88dSmrg{
67af69d88dSmrg   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
68af69d88dSmrg      return texImage->Height;
69af69d88dSmrg   else
70af69d88dSmrg      return texImage->Depth;
71af69d88dSmrg}
72af69d88dSmrg
73af69d88dSmrgunsigned int
74af69d88dSmrg_swrast_teximage_slice_height(struct gl_texture_image *texImage)
75af69d88dSmrg{
76af69d88dSmrg   /* For 1D array textures, the slices are all 1 pixel high, and Height is
77af69d88dSmrg    * the number of slices.
78af69d88dSmrg    */
79af69d88dSmrg   if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
80af69d88dSmrg      return 1;
81af69d88dSmrg   else
82af69d88dSmrg      return texImage->Height;
83af69d88dSmrg}
84af69d88dSmrg
85af69d88dSmrg/**
86af69d88dSmrg * Called via ctx->Driver.AllocTextureImageBuffer()
87af69d88dSmrg */
88af69d88dSmrgGLboolean
89af69d88dSmrg_swrast_alloc_texture_image_buffer(struct gl_context *ctx,
90af69d88dSmrg                                   struct gl_texture_image *texImage)
91af69d88dSmrg{
92af69d88dSmrg   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
93af69d88dSmrg   GLuint bytesPerSlice;
94af69d88dSmrg   GLuint slices = texture_slices(texImage);
95af69d88dSmrg   GLuint i;
96af69d88dSmrg
97af69d88dSmrg   if (!_swrast_init_texture_image(texImage))
98af69d88dSmrg      return GL_FALSE;
99af69d88dSmrg
100af69d88dSmrg   bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
101af69d88dSmrg                                           _swrast_teximage_slice_height(texImage), 1);
102af69d88dSmrg
103af69d88dSmrg   assert(!swImg->Buffer);
1047ec681f3Smrg   swImg->Buffer = align_malloc(bytesPerSlice * slices, 512);
105af69d88dSmrg   if (!swImg->Buffer)
106af69d88dSmrg      return GL_FALSE;
107af69d88dSmrg
108af69d88dSmrg   /* RowStride and ImageSlices[] describe how to address texels in 'Data' */
109af69d88dSmrg   swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
110af69d88dSmrg                                              texImage->Width);
111af69d88dSmrg
112af69d88dSmrg   for (i = 0; i < slices; i++) {
113af69d88dSmrg      swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
114af69d88dSmrg   }
115af69d88dSmrg
116af69d88dSmrg   return GL_TRUE;
117af69d88dSmrg}
118af69d88dSmrg
119af69d88dSmrg
120af69d88dSmrg/**
121af69d88dSmrg * Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
122af69d88dSmrg * initialize the fields of swrast_texture_image without allocating the image
123af69d88dSmrg * buffer or initializing RowStride or the contents of ImageSlices.
124af69d88dSmrg *
125af69d88dSmrg * Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
126af69d88dSmrg */
127af69d88dSmrgGLboolean
128af69d88dSmrg_swrast_init_texture_image(struct gl_texture_image *texImage)
129af69d88dSmrg{
130af69d88dSmrg   struct swrast_texture_image *swImg = swrast_texture_image(texImage);
131af69d88dSmrg
1327ec681f3Smrg   if ((texImage->Width == 1 || util_is_power_of_two_or_zero(texImage->Width2)) &&
1337ec681f3Smrg       (texImage->Height == 1 || util_is_power_of_two_or_zero(texImage->Height2)) &&
1347ec681f3Smrg       (texImage->Depth == 1 || util_is_power_of_two_or_zero(texImage->Depth2)))
135af69d88dSmrg      swImg->_IsPowerOfTwo = GL_TRUE;
136af69d88dSmrg   else
137af69d88dSmrg      swImg->_IsPowerOfTwo = GL_FALSE;
138af69d88dSmrg
139af69d88dSmrg   /* Compute Width/Height/DepthScale for mipmap lod computation */
140af69d88dSmrg   if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
141af69d88dSmrg      /* scale = 1.0 since texture coords directly map to texels */
142af69d88dSmrg      swImg->WidthScale = 1.0;
143af69d88dSmrg      swImg->HeightScale = 1.0;
144af69d88dSmrg      swImg->DepthScale = 1.0;
145af69d88dSmrg   }
146af69d88dSmrg   else {
147af69d88dSmrg      swImg->WidthScale = (GLfloat) texImage->Width;
148af69d88dSmrg      swImg->HeightScale = (GLfloat) texImage->Height;
149af69d88dSmrg      swImg->DepthScale = (GLfloat) texImage->Depth;
150af69d88dSmrg   }
151af69d88dSmrg
152af69d88dSmrg   assert(!swImg->ImageSlices);
153af69d88dSmrg   swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
154af69d88dSmrg   if (!swImg->ImageSlices)
155af69d88dSmrg      return GL_FALSE;
156af69d88dSmrg
157af69d88dSmrg   return GL_TRUE;
158af69d88dSmrg}
159af69d88dSmrg
160af69d88dSmrg
161af69d88dSmrg/**
162af69d88dSmrg * Called via ctx->Driver.FreeTextureImageBuffer()
163af69d88dSmrg */
164af69d88dSmrgvoid
165af69d88dSmrg_swrast_free_texture_image_buffer(struct gl_context *ctx,
166af69d88dSmrg                                  struct gl_texture_image *texImage)
167af69d88dSmrg{
168af69d88dSmrg   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
169af69d88dSmrg
1707ec681f3Smrg   align_free(swImage->Buffer);
171af69d88dSmrg   swImage->Buffer = NULL;
172af69d88dSmrg
173af69d88dSmrg   free(swImage->ImageSlices);
174af69d88dSmrg   swImage->ImageSlices = NULL;
175af69d88dSmrg}
176af69d88dSmrg
177af69d88dSmrg
178af69d88dSmrg/**
179af69d88dSmrg * Error checking for debugging only.
180af69d88dSmrg */
181af69d88dSmrgstatic void
182af69d88dSmrgcheck_map_teximage(const struct gl_texture_image *texImage,
183af69d88dSmrg                   GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
184af69d88dSmrg{
185af69d88dSmrg
186af69d88dSmrg   if (texImage->TexObject->Target == GL_TEXTURE_1D)
187af69d88dSmrg      assert(y == 0 && h == 1);
188af69d88dSmrg
189af69d88dSmrg   assert(x < texImage->Width || texImage->Width == 0);
190af69d88dSmrg   assert(y < texImage->Height || texImage->Height == 0);
191af69d88dSmrg   assert(x + w <= texImage->Width);
192af69d88dSmrg   assert(y + h <= texImage->Height);
19301e04c3fSmrg   assert(slice < texture_slices(texImage));
194af69d88dSmrg}
195af69d88dSmrg
196af69d88dSmrg/**
197af69d88dSmrg * Map a 2D slice of a texture image into user space.
198af69d88dSmrg * (x,y,w,h) defines a region of interest (ROI).  Reading/writing texels
199af69d88dSmrg * outside of the ROI is undefined.
200af69d88dSmrg *
201af69d88dSmrg * \param texImage  the texture image
202af69d88dSmrg * \param slice  the 3D image slice or array texture slice
203af69d88dSmrg * \param x, y, w, h  region of interest
204af69d88dSmrg * \param mode  bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
205af69d88dSmrg * \param mapOut  returns start of mapping of region of interest
206af69d88dSmrg * \param rowStrideOut  returns row stride (in bytes)
207af69d88dSmrg */
208af69d88dSmrgvoid
209af69d88dSmrg_swrast_map_teximage(struct gl_context *ctx,
210af69d88dSmrg                     struct gl_texture_image *texImage,
211af69d88dSmrg                     GLuint slice,
212af69d88dSmrg                     GLuint x, GLuint y, GLuint w, GLuint h,
213af69d88dSmrg                     GLbitfield mode,
214af69d88dSmrg                     GLubyte **mapOut,
215af69d88dSmrg                     GLint *rowStrideOut)
216af69d88dSmrg{
217af69d88dSmrg   struct swrast_texture_image *swImage = swrast_texture_image(texImage);
218af69d88dSmrg   GLubyte *map;
219af69d88dSmrg   GLint stride, texelSize;
220af69d88dSmrg   GLuint bw, bh;
221af69d88dSmrg
222af69d88dSmrg   check_map_teximage(texImage, slice, x, y, w, h);
223af69d88dSmrg
224af69d88dSmrg   if (!swImage->Buffer) {
225af69d88dSmrg      /* Either glTexImage was called with a NULL <pixels> argument or
226af69d88dSmrg       * we ran out of memory when allocating texture memory,
227af69d88dSmrg       */
228af69d88dSmrg      *mapOut = NULL;
229af69d88dSmrg      *rowStrideOut = 0;
230af69d88dSmrg      return;
231af69d88dSmrg   }
232af69d88dSmrg
233af69d88dSmrg   texelSize = _mesa_get_format_bytes(texImage->TexFormat);
234af69d88dSmrg   stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
235af69d88dSmrg   _mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
236af69d88dSmrg
237af69d88dSmrg   assert(x % bw == 0);
238af69d88dSmrg   assert(y % bh == 0);
239af69d88dSmrg
240af69d88dSmrg   /* This function can only be used with a swrast-allocated buffer, in which
241af69d88dSmrg    * case ImageSlices is populated with pointers into Buffer.
242af69d88dSmrg    */
243af69d88dSmrg   assert(swImage->Buffer);
244af69d88dSmrg   assert(swImage->Buffer == swImage->ImageSlices[0]);
245af69d88dSmrg
246af69d88dSmrg   map = swImage->ImageSlices[slice];
247af69d88dSmrg
248af69d88dSmrg   /* apply x/y offset to map address */
249af69d88dSmrg   map += stride * (y / bh) + texelSize * (x / bw);
250af69d88dSmrg
251af69d88dSmrg   *mapOut = map;
252af69d88dSmrg   *rowStrideOut = stride;
253af69d88dSmrg}
254af69d88dSmrg
255af69d88dSmrgvoid
256af69d88dSmrg_swrast_unmap_teximage(struct gl_context *ctx,
257af69d88dSmrg                       struct gl_texture_image *texImage,
258af69d88dSmrg                       GLuint slice)
259af69d88dSmrg{
260af69d88dSmrg   /* nop */
261af69d88dSmrg}
262af69d88dSmrg
263af69d88dSmrg
264af69d88dSmrgvoid
265af69d88dSmrg_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
266af69d88dSmrg{
267af69d88dSmrg   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
268af69d88dSmrg   GLuint face, level;
269af69d88dSmrg
270af69d88dSmrg   for (face = 0; face < faces; face++) {
2717ec681f3Smrg      for (level = texObj->Attrib.BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
272af69d88dSmrg         struct gl_texture_image *texImage = texObj->Image[face][level];
273af69d88dSmrg         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
274af69d88dSmrg         unsigned int i, slices;
275af69d88dSmrg
276af69d88dSmrg         if (!texImage)
277af69d88dSmrg            continue;
278af69d88dSmrg
279af69d88dSmrg         /* In the case of a swrast-allocated texture buffer, the ImageSlices
280af69d88dSmrg          * and RowStride are always available.
281af69d88dSmrg          */
282af69d88dSmrg         if (swImage->Buffer) {
283af69d88dSmrg            assert(swImage->ImageSlices[0] == swImage->Buffer);
284af69d88dSmrg            continue;
285af69d88dSmrg         }
286af69d88dSmrg
287af69d88dSmrg         if (!swImage->ImageSlices) {
288af69d88dSmrg            swImage->ImageSlices =
289af69d88dSmrg               calloc(texture_slices(texImage), sizeof(void *));
290af69d88dSmrg            if (!swImage->ImageSlices)
291af69d88dSmrg               continue;
292af69d88dSmrg         }
293af69d88dSmrg
294af69d88dSmrg         slices = texture_slices(texImage);
295af69d88dSmrg
296af69d88dSmrg         for (i = 0; i < slices; i++) {
297af69d88dSmrg            GLubyte *map;
298af69d88dSmrg            GLint rowStride;
299af69d88dSmrg
300af69d88dSmrg            if (swImage->ImageSlices[i])
301af69d88dSmrg               continue;
302af69d88dSmrg
303af69d88dSmrg            ctx->Driver.MapTextureImage(ctx, texImage, i,
304af69d88dSmrg                                        0, 0,
305af69d88dSmrg                                        texImage->Width, texImage->Height,
306af69d88dSmrg                                        GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
307af69d88dSmrg                                        &map, &rowStride);
308af69d88dSmrg
309af69d88dSmrg            swImage->ImageSlices[i] = map;
310af69d88dSmrg            /* A swrast-using driver has to return the same rowstride for
311af69d88dSmrg             * every slice of the same texture, since we don't track them
312af69d88dSmrg             * separately.
313af69d88dSmrg             */
314af69d88dSmrg            if (i == 0)
315af69d88dSmrg               swImage->RowStride = rowStride;
316af69d88dSmrg            else
317af69d88dSmrg               assert(swImage->RowStride == rowStride);
318af69d88dSmrg         }
319af69d88dSmrg      }
320af69d88dSmrg   }
321af69d88dSmrg}
322af69d88dSmrg
323af69d88dSmrg
324af69d88dSmrgvoid
325af69d88dSmrg_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
326af69d88dSmrg{
327af69d88dSmrg   const GLuint faces = _mesa_num_tex_faces(texObj->Target);
328af69d88dSmrg   GLuint face, level;
329af69d88dSmrg
330af69d88dSmrg   for (face = 0; face < faces; face++) {
3317ec681f3Smrg      for (level = texObj->Attrib.BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
332af69d88dSmrg         struct gl_texture_image *texImage = texObj->Image[face][level];
333af69d88dSmrg         struct swrast_texture_image *swImage = swrast_texture_image(texImage);
334af69d88dSmrg         unsigned int i, slices;
335af69d88dSmrg
336af69d88dSmrg         if (!texImage)
337af69d88dSmrg            continue;
338af69d88dSmrg
339af69d88dSmrg         if (swImage->Buffer)
340af69d88dSmrg            return;
341af69d88dSmrg
342af69d88dSmrg         if (!swImage->ImageSlices)
343af69d88dSmrg            continue;
344af69d88dSmrg
345af69d88dSmrg         slices = texture_slices(texImage);
346af69d88dSmrg
347af69d88dSmrg         for (i = 0; i < slices; i++) {
348af69d88dSmrg            if (swImage->ImageSlices[i]) {
349af69d88dSmrg               ctx->Driver.UnmapTextureImage(ctx, texImage, i);
350af69d88dSmrg               swImage->ImageSlices[i] = NULL;
351af69d88dSmrg            }
352af69d88dSmrg         }
353af69d88dSmrg      }
354af69d88dSmrg   }
355af69d88dSmrg}
356af69d88dSmrg
357af69d88dSmrg
358af69d88dSmrg/**
359af69d88dSmrg * Map all textures for reading prior to software rendering.
360af69d88dSmrg */
361af69d88dSmrgvoid
362af69d88dSmrg_swrast_map_textures(struct gl_context *ctx)
363af69d88dSmrg{
364af69d88dSmrg   int unit;
365af69d88dSmrg
366af69d88dSmrg   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
367af69d88dSmrg      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
368af69d88dSmrg
369af69d88dSmrg      if (texObj)
370af69d88dSmrg         _swrast_map_texture(ctx, texObj);
371af69d88dSmrg   }
372af69d88dSmrg}
373af69d88dSmrg
374af69d88dSmrg
375af69d88dSmrg/**
376af69d88dSmrg * Unmap all textures for reading prior to software rendering.
377af69d88dSmrg */
378af69d88dSmrgvoid
379af69d88dSmrg_swrast_unmap_textures(struct gl_context *ctx)
380af69d88dSmrg{
381af69d88dSmrg   int unit;
382af69d88dSmrg   for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
383af69d88dSmrg      struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
384af69d88dSmrg
385af69d88dSmrg      if (texObj)
386af69d88dSmrg         _swrast_unmap_texture(ctx, texObj);
387af69d88dSmrg   }
388af69d88dSmrg}
389