mesa,meta: move gl_texture_object::TargetIndex initializations
[mesa.git] / src / mesa / drivers / common / meta_copy_image.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2014 Intel Corporation. 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 "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "glheader.h"
26 #include "context.h"
27 #include "enums.h"
28 #include "imports.h"
29 #include "macros.h"
30 #include "teximage.h"
31 #include "texobj.h"
32 #include "fbobject.h"
33 #include "buffers.h"
34 #include "state.h"
35 #include "mtypes.h"
36 #include "meta.h"
37
38 /**
39 * Create a texture image that wraps a renderbuffer.
40 */
41 static struct gl_texture_image *
42 wrap_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
43 {
44 GLenum texTarget;
45 struct gl_texture_object *texObj;
46 struct gl_texture_image *texImage;
47
48 if (rb->NumSamples > 1)
49 texTarget = GL_TEXTURE_2D_MULTISAMPLE;
50 else
51 texTarget = GL_TEXTURE_2D;
52
53 /* Texture ID is not significant since it never goes into the hash table */
54 texObj = ctx->Driver.NewTextureObject(ctx, 0, texTarget);
55 assert(texObj);
56 if (!texObj)
57 return NULL;
58
59 texImage = _mesa_get_tex_image(ctx, texObj, texTarget, 0);
60 assert(texImage);
61 if (!texImage)
62 return NULL;
63
64 if (!ctx->Driver.BindRenderbufferTexImage(ctx, rb, texImage)) {
65 _mesa_problem(ctx, "Failed to create texture from renderbuffer");
66 return NULL;
67 }
68
69 if (ctx->Driver.FinishRenderTexture && !rb->NeedsFinishRenderTexture) {
70 rb->NeedsFinishRenderTexture = true;
71 ctx->Driver.FinishRenderTexture(ctx, rb);
72 }
73
74 return texImage;
75 }
76
77
78 /* This function makes a texture view without bothering with all of the API
79 * checks. Most of them are the same for CopyTexSubImage so checking would
80 * be redundant. The one major difference is that we don't check for
81 * whether the texture is immutable or not. However, since the view will
82 * be created and then immediately destroyed, this should not be a problem.
83 */
84 static bool
85 make_view(struct gl_context *ctx, struct gl_texture_image *tex_image,
86 struct gl_texture_image **view_tex_image, GLuint *view_tex_name,
87 GLenum internal_format)
88 {
89 struct gl_texture_object *tex_obj = tex_image->TexObject;
90 struct gl_texture_object *view_tex_obj;
91 mesa_format tex_format;
92
93 /* Set up the new texture object */
94 _mesa_GenTextures(1, view_tex_name);
95 view_tex_obj = _mesa_lookup_texture(ctx, *view_tex_name);
96 if (!view_tex_obj)
97 return false;
98
99 tex_format = _mesa_choose_texture_format(ctx, view_tex_obj, tex_obj->Target,
100 0, internal_format,
101 GL_NONE, GL_NONE);
102
103 if (!ctx->Driver.TestProxyTexImage(ctx, tex_obj->Target, 0, tex_format,
104 tex_image->Width, tex_image->Height,
105 tex_image->Depth, 0)) {
106 _mesa_DeleteTextures(1, view_tex_name);
107 *view_tex_name = 0;
108 return false;
109 }
110
111 assert(tex_obj->Target != 0);
112 assert(tex_obj->TargetIndex < NUM_TEXTURE_TARGETS);
113
114 view_tex_obj->Target = tex_obj->Target;
115 view_tex_obj->TargetIndex = tex_obj->TargetIndex;
116
117 *view_tex_image = _mesa_get_tex_image(ctx, view_tex_obj, tex_obj->Target, 0);
118
119 if (!*view_tex_image) {
120 _mesa_DeleteTextures(1, view_tex_name);
121 *view_tex_name = 0;
122 return false;
123 }
124
125 _mesa_init_teximage_fields(ctx, *view_tex_image,
126 tex_image->Width, tex_image->Height,
127 tex_image->Depth,
128 0, internal_format, tex_format);
129
130 view_tex_obj->MinLevel = tex_image->Level;
131 view_tex_obj->NumLevels = 1;
132 view_tex_obj->MinLayer = tex_obj->MinLayer;
133 view_tex_obj->NumLayers = tex_obj->NumLayers;
134 view_tex_obj->Immutable = tex_obj->Immutable;
135 view_tex_obj->ImmutableLevels = tex_obj->ImmutableLevels;
136
137 if (ctx->Driver.TextureView != NULL &&
138 !ctx->Driver.TextureView(ctx, view_tex_obj, tex_obj)) {
139 _mesa_DeleteTextures(1, view_tex_name);
140 *view_tex_name = 0;
141 return false; /* driver recorded error */
142 }
143
144 return true;
145 }
146
147 /** A partial implementation of glCopyImageSubData
148 *
149 * This is a partial implementation of glCopyImageSubData that works only
150 * if both textures are uncompressed and the destination texture is
151 * renderable. It uses a slight abuse of a texture view (see make_view) to
152 * turn the source texture into the destination texture type and then uses
153 * _mesa_meta_BlitFramebuffers to do the copy.
154 */
155 bool
156 _mesa_meta_CopyImageSubData_uncompressed(struct gl_context *ctx,
157 struct gl_texture_image *src_tex_image,
158 struct gl_renderbuffer *src_renderbuffer,
159 int src_x, int src_y, int src_z,
160 struct gl_texture_image *dst_tex_image,
161 struct gl_renderbuffer *dst_renderbuffer,
162 int dst_x, int dst_y, int dst_z,
163 int src_width, int src_height)
164 {
165 mesa_format src_format, dst_format;
166 GLint src_internal_format, dst_internal_format;
167 GLuint src_view_texture = 0;
168 struct gl_texture_image *src_view_tex_image;
169 GLuint fbos[2];
170 bool success = false;
171 GLbitfield mask;
172 GLenum status, attachment;
173
174 if (src_renderbuffer) {
175 src_format = src_renderbuffer->Format;
176 src_internal_format = src_renderbuffer->InternalFormat;
177 } else {
178 assert(src_tex_image);
179 src_format = src_tex_image->TexFormat;
180 src_internal_format = src_tex_image->InternalFormat;
181 }
182
183 if (dst_renderbuffer) {
184 dst_format = dst_renderbuffer->Format;
185 dst_internal_format = dst_renderbuffer->InternalFormat;
186 } else {
187 assert(dst_tex_image);
188 dst_format = dst_tex_image->TexFormat;
189 dst_internal_format = dst_tex_image->InternalFormat;
190 }
191
192 if (_mesa_is_format_compressed(src_format))
193 return false;
194
195 if (_mesa_is_format_compressed(dst_format))
196 return false;
197
198 if (src_internal_format == dst_internal_format) {
199 src_view_tex_image = src_tex_image;
200 } else {
201 if (src_renderbuffer) {
202 assert(src_tex_image == NULL);
203 src_tex_image = wrap_renderbuffer(ctx, src_renderbuffer);
204 }
205 if (!make_view(ctx, src_tex_image, &src_view_tex_image, &src_view_texture,
206 dst_tex_image->InternalFormat))
207 goto cleanup;
208 }
209
210 /* We really only need to stash the bound framebuffers and scissor. */
211 _mesa_meta_begin(ctx, MESA_META_SCISSOR);
212
213 _mesa_GenFramebuffers(2, fbos);
214 _mesa_BindFramebuffer(GL_READ_FRAMEBUFFER, fbos[0]);
215 _mesa_BindFramebuffer(GL_DRAW_FRAMEBUFFER, fbos[1]);
216
217 switch (_mesa_get_format_base_format(src_format)) {
218 case GL_DEPTH_COMPONENT:
219 attachment = GL_DEPTH_ATTACHMENT;
220 mask = GL_DEPTH_BUFFER_BIT;
221 break;
222 case GL_DEPTH_STENCIL:
223 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
224 mask = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
225 break;
226 case GL_STENCIL_INDEX:
227 attachment = GL_STENCIL_ATTACHMENT;
228 mask = GL_STENCIL_BUFFER_BIT;
229 break;
230 default:
231 attachment = GL_COLOR_ATTACHMENT0;
232 mask = GL_COLOR_BUFFER_BIT;
233 _mesa_DrawBuffer(GL_COLOR_ATTACHMENT0);
234 _mesa_ReadBuffer(GL_COLOR_ATTACHMENT0);
235 }
236
237 if (src_view_tex_image) {
238 /* Prever the tex image because, even if we have a renderbuffer, we may
239 * have had to wrap it in a texture view.
240 */
241 _mesa_meta_bind_fbo_image(GL_READ_FRAMEBUFFER, attachment,
242 src_view_tex_image, src_z);
243 } else {
244 _mesa_FramebufferRenderbuffer(GL_READ_FRAMEBUFFER,
245 attachment,
246 GL_RENDERBUFFER,
247 src_renderbuffer->Name);
248 }
249
250 status = _mesa_CheckFramebufferStatus(GL_READ_FRAMEBUFFER);
251 if (status != GL_FRAMEBUFFER_COMPLETE)
252 goto meta_end;
253
254 if (dst_renderbuffer) {
255 _mesa_FramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER,
256 attachment,
257 GL_RENDERBUFFER,
258 dst_renderbuffer->Name);
259 } else {
260 _mesa_meta_bind_fbo_image(GL_DRAW_FRAMEBUFFER, attachment,
261 dst_tex_image, dst_z);
262 }
263
264 status = _mesa_CheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
265 if (status != GL_FRAMEBUFFER_COMPLETE)
266 goto meta_end;
267
268 /* Since we've bound a new draw framebuffer, we need to update its
269 * derived state -- _Xmin, etc -- for BlitFramebuffer's clipping to
270 * be correct.
271 */
272 _mesa_update_state(ctx);
273
274 /* We skip the core BlitFramebuffer checks for format consistency.
275 * We have already created views to ensure that the texture formats
276 * match.
277 */
278 ctx->Driver.BlitFramebuffer(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
279 src_x, src_y,
280 src_x + src_width, src_y + src_height,
281 dst_x, dst_y,
282 dst_x + src_width, dst_y + src_height,
283 mask, GL_NEAREST);
284
285 success = true;
286
287 meta_end:
288 _mesa_DeleteFramebuffers(2, fbos);
289 _mesa_meta_end(ctx);
290
291 cleanup:
292 _mesa_DeleteTextures(1, &src_view_texture);
293
294 /* If we got a renderbuffer source, delete the temporary texture */
295 if (src_renderbuffer && src_tex_image)
296 ctx->Driver.DeleteTexture(ctx, src_tex_image->TexObject);
297
298 return success;
299 }