1 /**************************************************************************
2  *
3  * Copyright 2003 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "main/glheader.h"
29 #include "main/enums.h"
30 #include "main/mtypes.h"
31 #include "main/macros.h"
32 #include "main/fbobject.h"
33 #include "main/image.h"
34 #include "main/bufferobj.h"
35 #include "main/readpix.h"
36 #include "main/state.h"
37 
38 #include "intel_screen.h"
39 #include "intel_context.h"
40 #include "intel_blit.h"
41 #include "intel_buffers.h"
42 #include "intel_fbo.h"
43 #include "intel_mipmap_tree.h"
44 #include "intel_regions.h"
45 #include "intel_pixel.h"
46 #include "intel_buffer_objects.h"
47 
48 #define FILE_DEBUG_FLAG DEBUG_PIXEL
49 
50 /* For many applications, the new ability to pull the source buffers
51  * back out of the GTT and then do the packing/conversion operations
52  * in software will be as much of an improvement as trying to get the
53  * blitter and/or texture engine to do the work.
54  *
55  * This step is gated on private backbuffers.
56  *
57  * Obviously the frontbuffer can't be pulled back, so that is either
58  * an argument for blit/texture readpixels, or for blitting to a
59  * temporary and then pulling that back.
60  *
61  * When the destination is a pbo, however, it's not clear if it is
62  * ever going to be pulled to main memory (though the access param
63  * will be a good hint).  So it sounds like we do want to be able to
64  * choose between blit/texture implementation on the gpu and pullback
65  * and cpu-based copying.
66  *
67  * Unless you can magically turn client memory into a PBO for the
68  * duration of this call, there will be a cpu-based copying step in
69  * any case.
70  */
71 
72 static bool
do_blit_readpixels(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,const struct gl_pixelstore_attrib * pack,GLvoid * pixels)73 do_blit_readpixels(struct gl_context * ctx,
74                    GLint x, GLint y, GLsizei width, GLsizei height,
75                    GLenum format, GLenum type,
76                    const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
77 {
78    struct intel_context *intel = intel_context(ctx);
79    struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj);
80    GLuint dst_offset;
81    drm_intel_bo *dst_buffer;
82    GLint dst_x, dst_y;
83    GLuint dirty;
84 
85    DBG("%s\n", __func__);
86 
87    assert(pack->BufferObj);
88 
89    struct gl_renderbuffer *rb = ctx->ReadBuffer->_ColorReadBuffer;
90    struct intel_renderbuffer *irb = intel_renderbuffer(rb);
91 
92    if (ctx->_ImageTransferState ||
93        !_mesa_format_matches_format_and_type(irb->mt->format, format, type,
94                                              false, NULL)) {
95       DBG("%s - bad format for blit\n", __func__);
96       return false;
97    }
98 
99    if (pack->SwapBytes || pack->LsbFirst) {
100       DBG("%s: bad packing params\n", __func__);
101       return false;
102    }
103 
104    int dst_stride = _mesa_image_row_stride(pack, width, format, type);
105    bool dst_flip = false;
106    /* Mesa flips the dst_stride for pack->Invert, but we want our mt to have a
107     * normal dst_stride.
108     */
109    if (pack->Invert) {
110       dst_stride = -dst_stride;
111       dst_flip = true;
112    }
113 
114    dst_offset = (GLintptr)pixels;
115    dst_offset += _mesa_image_offset(2, pack, width, height,
116 				    format, type, 0, 0, 0);
117 
118    if (!_mesa_clip_copytexsubimage(ctx,
119 				   &dst_x, &dst_y,
120 				   &x, &y,
121 				   &width, &height)) {
122       return true;
123    }
124 
125    dirty = intel->front_buffer_dirty;
126    intel_prepare_render(intel);
127    intel->front_buffer_dirty = dirty;
128 
129    dst_buffer = intel_bufferobj_buffer(intel, dst);
130 
131    struct intel_mipmap_tree *pbo_mt =
132       intel_miptree_create_for_bo(intel,
133                                   dst_buffer,
134                                   irb->mt->format,
135                                   dst_offset,
136                                   width, height,
137                                   dst_stride, I915_TILING_NONE);
138 
139    if (!intel_miptree_blit(intel,
140                            irb->mt, irb->mt_level, irb->mt_layer,
141                            x, y, _mesa_is_winsys_fbo(ctx->ReadBuffer),
142                            pbo_mt, 0, 0,
143                            0, 0, dst_flip,
144                            width, height, COLOR_LOGICOP_COPY)) {
145       intel_miptree_release(&pbo_mt);
146       return false;
147    }
148 
149    intel_miptree_release(&pbo_mt);
150 
151    DBG("%s - DONE\n", __func__);
152 
153    return true;
154 }
155 
156 void
intelReadPixels(struct gl_context * ctx,GLint x,GLint y,GLsizei width,GLsizei height,GLenum format,GLenum type,const struct gl_pixelstore_attrib * pack,GLvoid * pixels)157 intelReadPixels(struct gl_context * ctx,
158                 GLint x, GLint y, GLsizei width, GLsizei height,
159                 GLenum format, GLenum type,
160                 const struct gl_pixelstore_attrib *pack, GLvoid * pixels)
161 {
162    struct intel_context *intel = intel_context(ctx);
163    bool dirty;
164 
165    intel_flush_rendering_to_batch(ctx);
166 
167    DBG("%s\n", __func__);
168 
169    if (pack->BufferObj) {
170       /* Using PBOs, so try the BLT based path. */
171       if (do_blit_readpixels(ctx, x, y, width, height, format, type, pack,
172                              pixels)) {
173          return;
174       }
175 
176       perf_debug("%s: fallback to CPU mapping in PBO case\n", __func__);
177    }
178 
179    /* glReadPixels() wont dirty the front buffer, so reset the dirty
180     * flag after calling intel_prepare_render(). */
181    dirty = intel->front_buffer_dirty;
182    intel_prepare_render(intel);
183    intel->front_buffer_dirty = dirty;
184 
185    /* Update Mesa state before calling _mesa_readpixels().
186     * XXX this may not be needed since ReadPixels no longer uses the
187     * span code.
188     */
189 
190    if (ctx->NewState)
191       _mesa_update_state(ctx);
192 
193    _mesa_readpixels(ctx, x, y, width, height, format, type, pack, pixels);
194 
195    /* There's an intel_prepare_render() call in intelSpanRenderStart(). */
196    intel->front_buffer_dirty = dirty;
197 }
198