• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 VMware, Inc.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portionsalloc
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "main/blend.h"
27 #include "main/enums.h"
28 #include "main/image.h"
29 #include "main/colormac.h"
30 #include "main/condrender.h"
31 #include "main/mtypes.h"
32 #include "main/macros.h"
33 #include "main/pbo.h"
34 #include "main/bufferobj.h"
35 #include "main/state.h"
36 #include "main/texobj.h"
37 #include "main/context.h"
38 #include "main/fbobject.h"
39 #include "swrast/swrast.h"
40 #include "drivers/common/meta.h"
41 
42 #include "brw_context.h"
43 #include "brw_screen.h"
44 #include "brw_batch.h"
45 #include "brw_blit.h"
46 #include "brw_fbo.h"
47 #include "brw_image.h"
48 #include "brw_buffers.h"
49 #include "brw_pixel.h"
50 
51 
52 #define FILE_DEBUG_FLAG DEBUG_PIXEL
53 
54 
55 /* Unlike the other intel_pixel_* functions, the expectation here is
56  * that the incoming data is not in a PBO.  With the XY_TEXT blit
57  * method, there's no benefit haveing it in a PBO, but we could
58  * implement a path based on XY_MONO_SRC_COPY_BLIT which might benefit
59  * PBO bitmaps.  I think they are probably pretty rare though - I
60  * wonder if Xgl uses them?
61  */
62 static const GLubyte *
map_pbo(struct gl_context * ctx,GLsizei width,GLsizei height,const struct gl_pixelstore_attrib * unpack,const GLubyte * bitmap)63 map_pbo(struct gl_context *ctx,
64         GLsizei width, GLsizei height,
65         const struct gl_pixelstore_attrib *unpack,
66         const GLubyte *bitmap)
67 {
68    GLubyte *buf;
69 
70    if (!_mesa_validate_pbo_access(2, unpack, width, height, 1,
71                                   GL_COLOR_INDEX, GL_BITMAP,
72                                   INT_MAX, (const GLvoid *) bitmap)) {
73       _mesa_error(ctx, GL_INVALID_OPERATION,"glBitmap(invalid PBO access)");
74       return NULL;
75    }
76 
77    buf = (GLubyte *) ctx->Driver.MapBufferRange(ctx, 0, unpack->BufferObj->Size,
78                                                 GL_MAP_READ_BIT,
79                                                 unpack->BufferObj,
80                                                 MAP_INTERNAL);
81    if (!buf) {
82       _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)");
83       return NULL;
84    }
85 
86    return ADD_POINTERS(buf, bitmap);
87 }
88 
test_bit(const GLubyte * src,GLuint bit)89 static bool test_bit( const GLubyte *src, GLuint bit )
90 {
91    return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0;
92 }
93 
set_bit(GLubyte * dest,GLuint bit)94 static void set_bit( GLubyte *dest, GLuint bit )
95 {
96    dest[bit/8] |= 1 << (bit % 8);
97 }
98 
99 /* Extract a rectangle's worth of data from the bitmap.  Called
100  * per chunk of HW-sized bitmap.
101  */
102 static GLuint
get_bitmap_rect(GLsizei width,GLsizei height,const struct gl_pixelstore_attrib * unpack,const GLubyte * bitmap,GLuint x,GLuint y,GLuint w,GLuint h,GLubyte * dest,GLuint row_align,bool invert)103 get_bitmap_rect(GLsizei width, GLsizei height,
104                 const struct gl_pixelstore_attrib *unpack,
105                 const GLubyte *bitmap,
106                 GLuint x, GLuint y,
107                 GLuint w, GLuint h,
108                 GLubyte *dest,
109                 GLuint row_align,
110                 bool invert)
111 {
112    GLuint src_offset = (x + unpack->SkipPixels) & 0x7;
113    GLuint mask = unpack->LsbFirst ? 0 : 7;
114    GLuint bit = 0;
115    GLint row, col;
116    GLint first, last;
117    GLint incr;
118    GLuint count = 0;
119 
120    DBG("%s %d,%d %dx%d bitmap %dx%d skip %d src_offset %d mask %d\n",
121        __func__, x,y,w,h,width,height,unpack->SkipPixels, src_offset, mask);
122 
123    if (invert) {
124       first = h-1;
125       last = 0;
126       incr = -1;
127    }
128    else {
129       first = 0;
130       last = h-1;
131       incr = 1;
132    }
133 
134    /* Require that dest be pre-zero'd.
135     */
136    for (row = first; row != (last+incr); row += incr) {
137       const GLubyte *rowsrc = _mesa_image_address2d(unpack, bitmap,
138                                                     width, height,
139                                                     GL_COLOR_INDEX, GL_BITMAP,
140                                                     y + row, x);
141 
142       for (col = 0; col < w; col++, bit++) {
143          if (test_bit(rowsrc, (col + src_offset) ^ mask)) {
144             set_bit(dest, bit ^ 7);
145             count++;
146          }
147       }
148 
149       if (row_align)
150          bit = ALIGN(bit, row_align);
151    }
152 
153    return count;
154 }
155 
156 /**
157  * Returns the low Y value of the vertical range given, flipped according to
158  * whether the framebuffer is or not.
159  */
160 static inline int
y_flip(struct gl_framebuffer * fb,int y,int height)161 y_flip(struct gl_framebuffer *fb, int y, int height)
162 {
163    if (fb->FlipY)
164       return fb->Height - y - height;
165    else
166       return y;
167 }
168 
169 /*
170  * Render a bitmap.
171  */
172 static bool
do_blit_bitmap(struct gl_context * ctx,GLint dstx,GLint dsty,GLsizei width,GLsizei height,const struct gl_pixelstore_attrib * unpack,const GLubyte * bitmap)173 do_blit_bitmap(struct gl_context *ctx,
174                GLint dstx, GLint dsty,
175                GLsizei width, GLsizei height,
176                const struct gl_pixelstore_attrib *unpack,
177                const GLubyte *bitmap)
178 {
179    struct brw_context *brw = brw_context(ctx);
180    struct gl_framebuffer *fb = ctx->DrawBuffer;
181    struct brw_renderbuffer *irb;
182    GLfloat tmpColor[4];
183    GLubyte ubcolor[4];
184    GLuint color;
185    GLsizei bitmap_width = width;
186    GLsizei bitmap_height = height;
187    GLint px, py;
188    GLuint stipple[32];
189    GLint orig_dstx = dstx;
190    GLint orig_dsty = dsty;
191 
192    /* Update draw buffer bounds */
193    _mesa_update_state(ctx);
194 
195    if (ctx->Depth.Test) {
196       /* The blit path produces incorrect results when depth testing is on.
197        * It seems the blit Z coord is always 1.0 (the far plane) so fragments
198        * will likely be obscured by other, closer geometry.
199        */
200       return false;
201    }
202 
203    brw_prepare_render(brw);
204 
205    if (fb->_NumColorDrawBuffers != 1) {
206       perf_debug("accelerated glBitmap() only supports rendering to a "
207                  "single color buffer\n");
208       return false;
209    }
210 
211    irb = brw_renderbuffer(fb->_ColorDrawBuffers[0]);
212 
213    if (unpack->BufferObj) {
214       bitmap = map_pbo(ctx, width, height, unpack, bitmap);
215       if (bitmap == NULL)
216          return true; /* even though this is an error, we're done */
217    }
218 
219    COPY_4V(tmpColor, ctx->Current.RasterColor);
220 
221    if (_mesa_need_secondary_color(ctx)) {
222        ADD_3V(tmpColor, tmpColor, ctx->Current.RasterSecondaryColor);
223    }
224 
225    UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[0], tmpColor[0]);
226    UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[1], tmpColor[1]);
227    UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[2], tmpColor[2]);
228    UNCLAMPED_FLOAT_TO_UBYTE(ubcolor[3], tmpColor[3]);
229 
230    switch (_mesa_get_render_format(ctx, brw_rb_format(irb))) {
231    case MESA_FORMAT_B8G8R8A8_UNORM:
232    case MESA_FORMAT_B8G8R8X8_UNORM:
233       color = PACK_COLOR_8888(ubcolor[3], ubcolor[0], ubcolor[1], ubcolor[2]);
234       break;
235    case MESA_FORMAT_B5G6R5_UNORM:
236       color = PACK_COLOR_565(ubcolor[0], ubcolor[1], ubcolor[2]);
237       break;
238    default:
239       perf_debug("Unsupported format %s in accelerated glBitmap()\n",
240                  _mesa_get_format_name(irb->mt->format));
241       return false;
242    }
243 
244    if (!brw_check_blit_fragment_ops(ctx, tmpColor[3] == 1.0F))
245       return false;
246 
247    /* Clip to buffer bounds and scissor. */
248    if (!_mesa_clip_to_region(fb->_Xmin, fb->_Ymin,
249                              fb->_Xmax, fb->_Ymax,
250                              &dstx, &dsty, &width, &height))
251       goto out;
252 
253    dsty = y_flip(fb, dsty, height);
254 
255 #define DY 32
256 #define DX 32
257 
258    /* The blitter has no idea about fast color clears, so we need to resolve
259     * the miptree before we do anything.
260     */
261    brw_miptree_access_raw(brw, irb->mt, irb->mt_level, irb->mt_layer, true);
262 
263    /* Chop it all into chunks that can be digested by hardware: */
264    for (py = 0; py < height; py += DY) {
265       for (px = 0; px < width; px += DX) {
266          int h = MIN2(DY, height - py);
267          int w = MIN2(DX, width - px);
268          GLuint sz = ALIGN(ALIGN(w,8) * h, 64)/8;
269          const enum gl_logicop_mode logic_op = ctx->Color.ColorLogicOpEnabled ?
270             ctx->Color._LogicOp : COLOR_LOGICOP_COPY;
271 
272          assert(sz <= sizeof(stipple));
273          memset(stipple, 0, sz);
274 
275          /* May need to adjust this when padding has been introduced in
276           * sz above:
277           *
278           * Have to translate destination coordinates back into source
279           * coordinates.
280           */
281          int count = get_bitmap_rect(bitmap_width, bitmap_height, unpack,
282                                      bitmap,
283                                      -orig_dstx + (dstx + px),
284                                      -orig_dsty + y_flip(fb, dsty + py, h),
285                                      w, h,
286                                      (GLubyte *)stipple,
287                                      8,
288                                      fb->FlipY);
289          if (count == 0)
290             continue;
291 
292          if (!brw_emit_immediate_color_expand_blit(brw,
293                                                    irb->mt->cpp,
294                                                    (GLubyte *)stipple,
295                                                    sz,
296                                                    color,
297                                                    irb->mt->surf.row_pitch_B,
298                                                    irb->mt->bo,
299                                                    irb->mt->offset,
300                                                    irb->mt->surf.tiling,
301                                                    dstx + px,
302                                                    dsty + py,
303                                                    w, h,
304                                                    logic_op)) {
305             return false;
306          }
307 
308          if (ctx->Query.CurrentOcclusionObject)
309             ctx->Query.CurrentOcclusionObject->Result += count;
310       }
311    }
312 out:
313 
314    if (INTEL_DEBUG(DEBUG_SYNC))
315       brw_batch_flush(brw);
316 
317    if (unpack->BufferObj) {
318       /* done with PBO so unmap it now */
319       ctx->Driver.UnmapBuffer(ctx, unpack->BufferObj, MAP_INTERNAL);
320    }
321 
322    return true;
323 }
324 
325 
326 /* There are a large number of possible ways to implement bitmap on
327  * this hardware, most of them have some sort of drawback.  Here are a
328  * few that spring to mind:
329  *
330  * Blit:
331  *    - XY_MONO_SRC_BLT_CMD
332  *         - use XY_SETUP_CLIP_BLT for cliprect clipping.
333  *    - XY_TEXT_BLT
334  *    - XY_TEXT_IMMEDIATE_BLT
335  *         - blit per cliprect, subject to maximum immediate data size.
336  *    - XY_COLOR_BLT
337  *         - per pixel or run of pixels
338  *    - XY_PIXEL_BLT
339  *         - good for sparse bitmaps
340  *
341  * 3D engine:
342  *    - Point per pixel
343  *    - Translate bitmap to an alpha texture and render as a quad
344  *    - Chop bitmap up into 32x32 squares and render w/polygon stipple.
345  */
346 void
brw_bitmap(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height,const struct gl_pixelstore_attrib * unpack,const GLubyte * pixels)347 brw_bitmap(struct gl_context * ctx,
348            GLint x, GLint y,
349            GLsizei width, GLsizei height,
350            const struct gl_pixelstore_attrib *unpack,
351            const GLubyte * pixels)
352 {
353    struct brw_context *brw = brw_context(ctx);
354 
355    if (!_mesa_check_conditional_render(ctx))
356       return;
357 
358    if (brw->screen->devinfo.ver < 6 &&
359        do_blit_bitmap(ctx, x, y, width, height, unpack, pixels))
360       return;
361 
362    _mesa_meta_Bitmap(ctx, x, y, width, height, unpack, pixels);
363 }
364