VirtualBox

source: vbox/trunk/src/VBox/Additions/WINNT/Graphics/Wine/wined3d/surface.c@ 30585

Last change on this file since 30585 was 28475, checked in by vboxsync, 15 years ago

crOpenGL: update to wine 1.1.43

  • Property svn:eol-style set to native
File size: 189.0 KB
Line 
1/*
2 * IWineD3DSurface Implementation
3 *
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007-2008 Henri Verbeet
12 * Copyright 2006-2008 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
14 *
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
19 *
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
24 *
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 */
29
30/*
31 * Sun LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
32 * other than GPL or LGPL is available it will apply instead, Sun elects to use only
33 * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
34 * a choice of LGPL license versions is made available with the language indicating
35 * that LGPLv2 or any later version may be used, or where a choice of which version
36 * of the LGPL is applied is otherwise unspecified.
37 */
38
39#include "config.h"
40#include "wine/port.h"
41#include "wined3d_private.h"
42
43WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
44WINE_DECLARE_DEBUG_CHANNEL(d3d);
45
46#define GLINFO_LOCATION (*gl_info)
47
48static void surface_cleanup(IWineD3DSurfaceImpl *This)
49{
50 IWineD3DDeviceImpl *device = This->resource.device;
51 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
52 struct wined3d_context *context = NULL;
53 renderbuffer_entry_t *entry, *entry2;
54
55 TRACE("(%p) : Cleaning up.\n", This);
56
57 /* Need a context to destroy the texture. Use the currently active render
58 * target, but only if the primary render target exists. Otherwise
59 * lastActiveRenderTarget is garbage. When destroying the primary render
60 * target, Uninit3D() will activate a context before doing anything. */
61 if (device->render_targets && device->render_targets[0])
62 {
63 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
64 }
65
66 ENTER_GL();
67
68 if (This->texture_name)
69 {
70 /* Release the OpenGL texture. */
71 TRACE("Deleting texture %u.\n", This->texture_name);
72 glDeleteTextures(1, &This->texture_name);
73 }
74
75 if (This->Flags & SFLAG_PBO)
76 {
77 /* Delete the PBO. */
78 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
79 }
80
81 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
82 {
83 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
84 HeapFree(GetProcessHeap(), 0, entry);
85 }
86
87 LEAVE_GL();
88
89 if (This->Flags & SFLAG_DIBSECTION)
90 {
91 /* Release the DC. */
92 SelectObject(This->hDC, This->dib.holdbitmap);
93 DeleteDC(This->hDC);
94 /* Release the DIB section. */
95 DeleteObject(This->dib.DIBsection);
96 This->dib.bitmap_data = NULL;
97 This->resource.allocatedMemory = NULL;
98 }
99
100 if (This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
101 if (This->overlay_dest) list_remove(&This->overlay_entry);
102
103 HeapFree(GetProcessHeap(), 0, This->palette9);
104
105 resource_cleanup((IWineD3DResource *)This);
106
107 if (context) context_release(context);
108}
109
110UINT surface_calculate_size(const struct wined3d_format_desc *format_desc, UINT alignment, UINT width, UINT height)
111{
112 UINT size;
113
114 if (format_desc->format == WINED3DFMT_UNKNOWN)
115 {
116 size = 0;
117 }
118 else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
119 {
120 UINT row_block_count = (width + format_desc->block_width - 1) / format_desc->block_width;
121 UINT row_count = (height + format_desc->block_height - 1) / format_desc->block_height;
122 size = row_count * row_block_count * format_desc->block_byte_count;
123 }
124 else
125 {
126 /* The pitch is a multiple of 4 bytes. */
127 size = height * (((width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1));
128 }
129
130 if (format_desc->heightscale != 0.0f) size *= format_desc->heightscale;
131
132 return size;
133}
134
135struct blt_info
136{
137 GLenum binding;
138 GLenum bind_target;
139 enum tex_types tex_type;
140 GLfloat coords[4][3];
141};
142
143struct float_rect
144{
145 float l;
146 float t;
147 float r;
148 float b;
149};
150
151static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
152{
153 f->l = ((r->left * 2.0f) / w) - 1.0f;
154 f->t = ((r->top * 2.0f) / h) - 1.0f;
155 f->r = ((r->right * 2.0f) / w) - 1.0f;
156 f->b = ((r->bottom * 2.0f) / h) - 1.0f;
157}
158
159static void surface_get_blt_info(GLenum target, const RECT *rect_in, GLsizei w, GLsizei h, struct blt_info *info)
160{
161 GLfloat (*coords)[3] = info->coords;
162 RECT rect;
163 struct float_rect f;
164
165 if (rect_in)
166 rect = *rect_in;
167 else
168 {
169 rect.left = 0;
170 rect.top = h;
171 rect.right = w;
172 rect.bottom = 0;
173 }
174
175 switch (target)
176 {
177 default:
178 FIXME("Unsupported texture target %#x\n", target);
179 /* Fall back to GL_TEXTURE_2D */
180 case GL_TEXTURE_2D:
181 info->binding = GL_TEXTURE_BINDING_2D;
182 info->bind_target = GL_TEXTURE_2D;
183 info->tex_type = tex_2d;
184 coords[0][0] = (float)rect.left / w;
185 coords[0][1] = (float)rect.top / h;
186 coords[0][2] = 0.0f;
187
188 coords[1][0] = (float)rect.right / w;
189 coords[1][1] = (float)rect.top / h;
190 coords[1][2] = 0.0f;
191
192 coords[2][0] = (float)rect.left / w;
193 coords[2][1] = (float)rect.bottom / h;
194 coords[2][2] = 0.0f;
195
196 coords[3][0] = (float)rect.right / w;
197 coords[3][1] = (float)rect.bottom / h;
198 coords[3][2] = 0.0f;
199 break;
200
201 case GL_TEXTURE_RECTANGLE_ARB:
202 info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
203 info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
204 info->tex_type = tex_rect;
205 coords[0][0] = rect.left; coords[0][1] = rect.top; coords[0][2] = 0.0f;
206 coords[1][0] = rect.right; coords[1][1] = rect.top; coords[1][2] = 0.0f;
207 coords[2][0] = rect.left; coords[2][1] = rect.bottom; coords[2][2] = 0.0f;
208 coords[3][0] = rect.right; coords[3][1] = rect.bottom; coords[3][2] = 0.0f;
209 break;
210
211 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
212 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
213 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
214 info->tex_type = tex_cube;
215 cube_coords_float(&rect, w, h, &f);
216
217 coords[0][0] = 1.0f; coords[0][1] = -f.t; coords[0][2] = -f.l;
218 coords[1][0] = 1.0f; coords[1][1] = -f.t; coords[1][2] = -f.r;
219 coords[2][0] = 1.0f; coords[2][1] = -f.b; coords[2][2] = -f.l;
220 coords[3][0] = 1.0f; coords[3][1] = -f.b; coords[3][2] = -f.r;
221 break;
222
223 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
224 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
225 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
226 info->tex_type = tex_cube;
227 cube_coords_float(&rect, w, h, &f);
228
229 coords[0][0] = -1.0f; coords[0][1] = -f.t; coords[0][2] = f.l;
230 coords[1][0] = -1.0f; coords[1][1] = -f.t; coords[1][2] = f.r;
231 coords[2][0] = -1.0f; coords[2][1] = -f.b; coords[2][2] = f.l;
232 coords[3][0] = -1.0f; coords[3][1] = -f.b; coords[3][2] = f.r;
233 break;
234
235 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
236 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
237 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
238 info->tex_type = tex_cube;
239 cube_coords_float(&rect, w, h, &f);
240
241 coords[0][0] = f.l; coords[0][1] = 1.0f; coords[0][2] = f.t;
242 coords[1][0] = f.r; coords[1][1] = 1.0f; coords[1][2] = f.t;
243 coords[2][0] = f.l; coords[2][1] = 1.0f; coords[2][2] = f.b;
244 coords[3][0] = f.r; coords[3][1] = 1.0f; coords[3][2] = f.b;
245 break;
246
247 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
248 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
249 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
250 info->tex_type = tex_cube;
251 cube_coords_float(&rect, w, h, &f);
252
253 coords[0][0] = f.l; coords[0][1] = -1.0f; coords[0][2] = -f.t;
254 coords[1][0] = f.r; coords[1][1] = -1.0f; coords[1][2] = -f.t;
255 coords[2][0] = f.l; coords[2][1] = -1.0f; coords[2][2] = -f.b;
256 coords[3][0] = f.r; coords[3][1] = -1.0f; coords[3][2] = -f.b;
257 break;
258
259 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
260 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
261 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
262 info->tex_type = tex_cube;
263 cube_coords_float(&rect, w, h, &f);
264
265 coords[0][0] = f.l; coords[0][1] = -f.t; coords[0][2] = 1.0f;
266 coords[1][0] = f.r; coords[1][1] = -f.t; coords[1][2] = 1.0f;
267 coords[2][0] = f.l; coords[2][1] = -f.b; coords[2][2] = 1.0f;
268 coords[3][0] = f.r; coords[3][1] = -f.b; coords[3][2] = 1.0f;
269 break;
270
271 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
272 info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
273 info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
274 info->tex_type = tex_cube;
275 cube_coords_float(&rect, w, h, &f);
276
277 coords[0][0] = -f.l; coords[0][1] = -f.t; coords[0][2] = -1.0f;
278 coords[1][0] = -f.r; coords[1][1] = -f.t; coords[1][2] = -1.0f;
279 coords[2][0] = -f.l; coords[2][1] = -f.b; coords[2][2] = -1.0f;
280 coords[3][0] = -f.r; coords[3][1] = -f.b; coords[3][2] = -1.0f;
281 break;
282 }
283}
284
285static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
286{
287 if (rect_in)
288 *rect_out = *rect_in;
289 else
290 {
291 rect_out->left = 0;
292 rect_out->top = 0;
293 rect_out->right = This->currentDesc.Width;
294 rect_out->bottom = This->currentDesc.Height;
295 }
296}
297
298/* GL locking and context activation is done by the caller */
299void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
300{
301 IWineD3DBaseTextureImpl *texture;
302 struct blt_info info;
303
304 surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
305
306 glEnable(info.bind_target);
307 checkGLcall("glEnable(bind_target)");
308
309 /* Bind the texture */
310 glBindTexture(info.bind_target, src_surface->texture_name);
311 checkGLcall("glBindTexture");
312
313 /* Filtering for StretchRect */
314 glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
315 wined3d_gl_mag_filter(magLookup, Filter));
316 checkGLcall("glTexParameteri");
317 glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
318 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
319 checkGLcall("glTexParameteri");
320 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
321 glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
322 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
323 checkGLcall("glTexEnvi");
324
325 /* Draw a quad */
326 glBegin(GL_TRIANGLE_STRIP);
327 glTexCoord3fv(info.coords[0]);
328 glVertex2i(dst_rect->left, dst_rect->top);
329
330 glTexCoord3fv(info.coords[1]);
331 glVertex2i(dst_rect->right, dst_rect->top);
332
333 glTexCoord3fv(info.coords[2]);
334 glVertex2i(dst_rect->left, dst_rect->bottom);
335
336 glTexCoord3fv(info.coords[3]);
337 glVertex2i(dst_rect->right, dst_rect->bottom);
338 glEnd();
339
340 /* Unbind the texture */
341 glBindTexture(info.bind_target, 0);
342 checkGLcall("glBindTexture(info->bind_target, 0)");
343
344 /* We changed the filtering settings on the texture. Inform the
345 * container about this to get the filters reset properly next draw. */
346 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)src_surface, &IID_IWineD3DBaseTexture, (void **)&texture)))
347 {
348 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
349 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
350 texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
351 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
352 }
353}
354
355HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
356 UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
357 UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format,
358 WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
359{
360 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
361 const struct wined3d_format_desc *format_desc = getFormatDescEntry(format, gl_info);
362 void (*cleanup)(IWineD3DSurfaceImpl *This);
363 unsigned int resource_size;
364 HRESULT hr;
365
366 if (multisample_quality > 0)
367 {
368 FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality);
369 multisample_quality = 0;
370 }
371
372 /* FIXME: Check that the format is supported by the device. */
373
374 resource_size = surface_calculate_size(format_desc, alignment, width, height);
375
376 /* Look at the implementation and set the correct Vtable. */
377 switch (surface_type)
378 {
379 case SURFACE_OPENGL:
380 surface->lpVtbl = &IWineD3DSurface_Vtbl;
381 cleanup = surface_cleanup;
382 break;
383
384 case SURFACE_GDI:
385 surface->lpVtbl = &IWineGDISurface_Vtbl;
386 cleanup = surface_gdi_cleanup;
387 break;
388
389 default:
390 ERR("Requested unknown surface implementation %#x.\n", surface_type);
391 return WINED3DERR_INVALIDCALL;
392 }
393
394 hr = resource_init((IWineD3DResource *)surface, WINED3DRTYPE_SURFACE,
395 device, resource_size, usage, format_desc, pool, parent, parent_ops);
396 if (FAILED(hr))
397 {
398 WARN("Failed to initialize resource, returning %#x.\n", hr);
399 return hr;
400 }
401
402 /* "Standalone" surface. */
403 IWineD3DSurface_SetContainer((IWineD3DSurface *)surface, NULL);
404
405 surface->currentDesc.Width = width;
406 surface->currentDesc.Height = height;
407 surface->currentDesc.MultiSampleType = multisample_type;
408 surface->currentDesc.MultiSampleQuality = multisample_quality;
409 surface->texture_level = level;
410 list_init(&surface->overlays);
411
412 /* Flags */
413 surface->Flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
414 if (discard) surface->Flags |= SFLAG_DISCARD;
415 if (lockable || format == WINED3DFMT_D16_LOCKABLE) surface->Flags |= SFLAG_LOCKABLE;
416
417 /* Quick lockable sanity check.
418 * TODO: remove this after surfaces, usage and lockability have been debugged properly
419 * this function is too deep to need to care about things like this.
420 * Levels need to be checked too, since they all affect what can be done. */
421 switch (pool)
422 {
423 case WINED3DPOOL_SCRATCH:
424 if(!lockable)
425 {
426 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
427 "which are mutually exclusive, setting lockable to TRUE.\n");
428 lockable = TRUE;
429 }
430 break;
431
432 case WINED3DPOOL_SYSTEMMEM:
433 if (!lockable)
434 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
435 break;
436
437 case WINED3DPOOL_MANAGED:
438 if (usage & WINED3DUSAGE_DYNAMIC)
439 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
440 break;
441
442 case WINED3DPOOL_DEFAULT:
443 if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
444 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
445 break;
446
447 default:
448 FIXME("Unknown pool %#x.\n", pool);
449 break;
450 };
451
452 if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
453 {
454 FIXME("Trying to create a render target that isn't in the default pool.\n");
455 }
456
457 /* Mark the texture as dirty so that it gets loaded first time around. */
458 surface_add_dirty_rect((IWineD3DSurface *)surface, NULL);
459 list_init(&surface->renderbuffers);
460
461 TRACE("surface %p, memory %p, size %u\n", surface, surface->resource.allocatedMemory, surface->resource.size);
462
463 /* Call the private setup routine */
464 hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)surface);
465 if (FAILED(hr))
466 {
467 ERR("Private setup failed, returning %#x\n", hr);
468 cleanup(surface);
469 return hr;
470 }
471
472 return hr;
473}
474
475static void surface_force_reload(IWineD3DSurface *iface)
476{
477 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
478
479 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
480}
481
482void surface_set_texture_name(IWineD3DSurface *iface, GLuint new_name, BOOL srgb)
483{
484 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
485 GLuint *name;
486 DWORD flag;
487
488 if(srgb)
489 {
490 name = &This->texture_name_srgb;
491 flag = SFLAG_INSRGBTEX;
492 }
493 else
494 {
495 name = &This->texture_name;
496 flag = SFLAG_INTEXTURE;
497 }
498
499 TRACE("(%p) : setting texture name %u\n", This, new_name);
500
501 if (!*name && new_name)
502 {
503 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
504 * surface has no texture name yet. See if we can get rid of this. */
505 if (This->Flags & flag)
506 ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n");
507 IWineD3DSurface_ModifyLocation(iface, flag, FALSE);
508 }
509
510 *name = new_name;
511 surface_force_reload(iface);
512}
513
514void surface_set_texture_target(IWineD3DSurface *iface, GLenum target)
515{
516 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
517
518 TRACE("(%p) : setting target %#x\n", This, target);
519
520 if (This->texture_target != target)
521 {
522 if (target == GL_TEXTURE_RECTANGLE_ARB)
523 {
524 This->Flags &= ~SFLAG_NORMCOORD;
525 }
526 else if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
527 {
528 This->Flags |= SFLAG_NORMCOORD;
529 }
530 }
531 This->texture_target = target;
532 surface_force_reload(iface);
533}
534
535/* Context activation is done by the caller. */
536static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) {
537 DWORD active_sampler;
538
539 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
540 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
541 * gl states. The current texture unit should always be a valid one.
542 *
543 * To be more specific, this is tricky because we can implicitly be called
544 * from sampler() in state.c. This means we can't touch anything other than
545 * whatever happens to be the currently active texture, or we would risk
546 * marking already applied sampler states dirty again.
547 *
548 * TODO: Track the current active texture per GL context instead of using glGet
549 */
550 GLint active_texture=GL_TEXTURE0_ARB;
551 ENTER_GL();
552 glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
553 LEAVE_GL();
554 active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
555
556 if (active_sampler != WINED3D_UNMAPPED_STAGE)
557 {
558 IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler));
559 }
560 IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb);
561}
562
563/* This function checks if the primary render target uses the 8bit paletted format. */
564static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
565{
566 if (device->render_targets && device->render_targets[0]) {
567 IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
568 if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
569 && (render_target->resource.format_desc->format == WINED3DFMT_P8_UINT))
570 return TRUE;
571 }
572 return FALSE;
573}
574
575/* This call just downloads data, the caller is responsible for binding the
576 * correct texture. */
577/* Context activation is done by the caller. */
578static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
579{
580 const struct wined3d_format_desc *format_desc = This->resource.format_desc;
581
582 /* Only support read back of converted P8 surfaces */
583 if (This->Flags & SFLAG_CONVERTED && format_desc->format != WINED3DFMT_P8_UINT)
584 {
585 FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc->format));
586 return;
587 }
588
589 ENTER_GL();
590
591 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
592 {
593 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
594 This, This->texture_level, format_desc->glFormat, format_desc->glType,
595 This->resource.allocatedMemory);
596
597 if (This->Flags & SFLAG_PBO)
598 {
599 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
600 checkGLcall("glBindBufferARB");
601 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
602 checkGLcall("glGetCompressedTexImageARB");
603 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
604 checkGLcall("glBindBufferARB");
605 }
606 else
607 {
608 GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
609 This->texture_level, This->resource.allocatedMemory));
610 checkGLcall("glGetCompressedTexImageARB");
611 }
612
613 LEAVE_GL();
614 } else {
615 void *mem;
616 GLenum format = format_desc->glFormat;
617 GLenum type = format_desc->glType;
618 int src_pitch = 0;
619 int dst_pitch = 0;
620
621 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
622 if (format_desc->format == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
623 {
624 format = GL_ALPHA;
625 type = GL_UNSIGNED_BYTE;
626 }
627
628 if (This->Flags & SFLAG_NONPOW2) {
629 unsigned char alignment = This->resource.device->surface_alignment;
630 src_pitch = format_desc->byte_count * This->pow2Width;
631 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
632 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
633 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
634 } else {
635 mem = This->resource.allocatedMemory;
636 }
637
638 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
639 This, This->texture_level, format, type, mem);
640
641 if(This->Flags & SFLAG_PBO) {
642 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
643 checkGLcall("glBindBufferARB");
644
645 glGetTexImage(This->texture_target, This->texture_level, format, type, NULL);
646 checkGLcall("glGetTexImage");
647
648 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
649 checkGLcall("glBindBufferARB");
650 } else {
651 glGetTexImage(This->texture_target, This->texture_level, format, type, mem);
652 checkGLcall("glGetTexImage");
653 }
654 LEAVE_GL();
655
656 if (This->Flags & SFLAG_NONPOW2) {
657 const BYTE *src_data;
658 BYTE *dst_data;
659 UINT y;
660 /*
661 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
662 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
663 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
664 *
665 * We're doing this...
666 *
667 * instead of boxing the texture :
668 * |<-texture width ->| -->pow2width| /\
669 * |111111111111111111| | |
670 * |222 Texture 222222| boxed empty | texture height
671 * |3333 Data 33333333| | |
672 * |444444444444444444| | \/
673 * ----------------------------------- |
674 * | boxed empty | boxed empty | pow2height
675 * | | | \/
676 * -----------------------------------
677 *
678 *
679 * we're repacking the data to the expected texture width
680 *
681 * |<-texture width ->| -->pow2width| /\
682 * |111111111111111111222222222222222| |
683 * |222333333333333333333444444444444| texture height
684 * |444444 | |
685 * | | \/
686 * | | |
687 * | empty | pow2height
688 * | | \/
689 * -----------------------------------
690 *
691 * == is the same as
692 *
693 * |<-texture width ->| /\
694 * |111111111111111111|
695 * |222222222222222222|texture height
696 * |333333333333333333|
697 * |444444444444444444| \/
698 * --------------------
699 *
700 * this also means that any references to allocatedMemory should work with the data as if were a
701 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
702 *
703 * internally the texture is still stored in a boxed format so any references to textureName will
704 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
705 *
706 * Performance should not be an issue, because applications normally do not lock the surfaces when
707 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
708 * and doesn't have to be re-read.
709 */
710 src_data = mem;
711 dst_data = This->resource.allocatedMemory;
712 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
713 for (y = 1 ; y < This->currentDesc.Height; y++) {
714 /* skip the first row */
715 src_data += src_pitch;
716 dst_data += dst_pitch;
717 memcpy(dst_data, src_data, dst_pitch);
718 }
719
720 HeapFree(GetProcessHeap(), 0, mem);
721 }
722 }
723
724 /* Surface has now been downloaded */
725 This->Flags |= SFLAG_INSYSMEM;
726}
727
728/* This call just uploads data, the caller is responsible for binding the
729 * correct texture. */
730/* Context activation is done by the caller. */
731static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
732 const struct wined3d_format_desc *format_desc, BOOL srgb, const GLvoid *data)
733{
734 GLsizei width = This->currentDesc.Width;
735 GLsizei height = This->currentDesc.Height;
736 GLenum internal;
737
738 if (srgb)
739 {
740 internal = format_desc->glGammaInternal;
741 }
742 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
743 && surface_is_offscreen((IWineD3DSurface *)This))
744 {
745 internal = format_desc->rtInternal;
746 }
747 else
748 {
749 internal = format_desc->glInternal;
750 }
751
752 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
753 This, internal, width, height, format_desc->glFormat, format_desc->glType, data);
754 TRACE("target %#x, level %u, resource size %u.\n",
755 This->texture_target, This->texture_level, This->resource.size);
756
757 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
758
759 ENTER_GL();
760
761 if (This->Flags & SFLAG_PBO)
762 {
763 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
764 checkGLcall("glBindBufferARB");
765
766 TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
767 data = NULL;
768 }
769
770 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
771 {
772 TRACE("Calling glCompressedTexSubImage2DARB.\n");
773
774 GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
775 0, 0, width, height, internal, This->resource.size, data));
776 checkGLcall("glCompressedTexSubImage2DARB");
777 }
778 else
779 {
780 TRACE("Calling glTexSubImage2D.\n");
781
782 glTexSubImage2D(This->texture_target, This->texture_level,
783 0, 0, width, height, format_desc->glFormat, format_desc->glType, data);
784 checkGLcall("glTexSubImage2D");
785 }
786
787 if (This->Flags & SFLAG_PBO)
788 {
789 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
790 checkGLcall("glBindBufferARB");
791 }
792
793 LEAVE_GL();
794
795 if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
796 {
797 IWineD3DDeviceImpl *device = This->resource.device;
798 unsigned int i;
799
800 for (i = 0; i < device->numContexts; ++i)
801 {
802 context_surface_update(device->contexts[i], This);
803 }
804 }
805}
806
807/* This call just allocates the texture, the caller is responsible for binding
808 * the correct texture. */
809/* Context activation is done by the caller. */
810static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
811 const struct wined3d_format_desc *format_desc, BOOL srgb)
812{
813 BOOL enable_client_storage = FALSE;
814 GLsizei width = This->pow2Width;
815 GLsizei height = This->pow2Height;
816 const BYTE *mem = NULL;
817 GLenum internal;
818
819 if (srgb)
820 {
821 internal = format_desc->glGammaInternal;
822 }
823 else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
824 && surface_is_offscreen((IWineD3DSurface *)This))
825 {
826 internal = format_desc->rtInternal;
827 }
828 else
829 {
830 internal = format_desc->glInternal;
831 }
832
833 if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
834
835 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
836 This, This->texture_target, This->texture_level, debug_d3dformat(format_desc->format),
837 internal, width, height, format_desc->glFormat, format_desc->glType);
838
839 ENTER_GL();
840
841 if (gl_info->supported[APPLE_CLIENT_STORAGE])
842 {
843 if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
844 /* In some cases we want to disable client storage.
845 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
846 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
847 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
848 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
849 */
850 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
851 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
852 This->Flags &= ~SFLAG_CLIENT;
853 enable_client_storage = TRUE;
854 } else {
855 This->Flags |= SFLAG_CLIENT;
856
857 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
858 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
859 */
860 mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
861 }
862 }
863
864 if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED && mem)
865 {
866 GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
867 internal, width, height, 0, This->resource.size, mem));
868 }
869 else
870 {
871 glTexImage2D(This->texture_target, This->texture_level,
872 internal, width, height, 0, format_desc->glFormat, format_desc->glType, mem);
873 checkGLcall("glTexImage2D");
874 }
875
876 if(enable_client_storage) {
877 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
878 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
879 }
880 LEAVE_GL();
881}
882
883/* In D3D the depth stencil dimensions have to be greater than or equal to the
884 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
885/* TODO: We should synchronize the renderbuffer's content with the texture's content. */
886/* GL locking is done by the caller */
887void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
888 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
889 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
890 renderbuffer_entry_t *entry;
891 GLuint renderbuffer = 0;
892 unsigned int src_width, src_height;
893
894 src_width = This->pow2Width;
895 src_height = This->pow2Height;
896
897 /* A depth stencil smaller than the render target is not valid */
898 if (width > src_width || height > src_height) return;
899
900 /* Remove any renderbuffer set if the sizes match */
901 if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
902 || (width == src_width && height == src_height))
903 {
904 This->current_renderbuffer = NULL;
905 return;
906 }
907
908 /* Look if we've already got a renderbuffer of the correct dimensions */
909 LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
910 if (entry->width == width && entry->height == height) {
911 renderbuffer = entry->id;
912 This->current_renderbuffer = entry;
913 break;
914 }
915 }
916
917 if (!renderbuffer) {
918 gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
919 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
920 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
921 This->resource.format_desc->glInternal, width, height);
922
923 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
924 entry->width = width;
925 entry->height = height;
926 entry->id = renderbuffer;
927 list_add_head(&This->renderbuffers, &entry->entry);
928
929 This->current_renderbuffer = entry;
930 }
931
932 checkGLcall("set_compatible_renderbuffer");
933}
934
935GLenum surface_get_gl_buffer(IWineD3DSurface *iface)
936{
937 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
938 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *)This->container;
939
940 TRACE("iface %p.\n", iface);
941
942 if (!(This->Flags & SFLAG_SWAPCHAIN))
943 {
944 ERR("Surface %p is not on a swapchain.\n", iface);
945 return GL_NONE;
946 }
947
948 if (swapchain->backBuffer && swapchain->backBuffer[0] == iface)
949 {
950 if (swapchain->render_to_fbo)
951 {
952 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
953 return GL_COLOR_ATTACHMENT0;
954 }
955 TRACE("Returning GL_BACK\n");
956 return GL_BACK;
957 }
958 else if (swapchain->frontBuffer == iface)
959 {
960 TRACE("Returning GL_FRONT\n");
961 return GL_FRONT;
962 }
963
964 FIXME("Higher back buffer, returning GL_BACK\n");
965 return GL_BACK;
966}
967
968/* Slightly inefficient way to handle multiple dirty rects but it works :) */
969void surface_add_dirty_rect(IWineD3DSurface *iface, const RECT *dirty_rect)
970{
971 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
972 IWineD3DBaseTexture *baseTexture = NULL;
973
974 if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
975 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
976
977 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
978 if (dirty_rect)
979 {
980 This->dirtyRect.left = min(This->dirtyRect.left, dirty_rect->left);
981 This->dirtyRect.top = min(This->dirtyRect.top, dirty_rect->top);
982 This->dirtyRect.right = max(This->dirtyRect.right, dirty_rect->right);
983 This->dirtyRect.bottom = max(This->dirtyRect.bottom, dirty_rect->bottom);
984 }
985 else
986 {
987 This->dirtyRect.left = 0;
988 This->dirtyRect.top = 0;
989 This->dirtyRect.right = This->currentDesc.Width;
990 This->dirtyRect.bottom = This->currentDesc.Height;
991 }
992
993 TRACE("(%p) : Dirty: yes, Rect:(%d, %d, %d, %d)\n", This, This->dirtyRect.left,
994 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
995
996 /* if the container is a basetexture then mark it dirty. */
997 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
998 {
999 TRACE("Passing to container\n");
1000 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
1001 IWineD3DBaseTexture_Release(baseTexture);
1002 }
1003}
1004
1005static BOOL surface_convert_color_to_argb(IWineD3DSurfaceImpl *This, DWORD color, DWORD *argb_color)
1006{
1007 IWineD3DDeviceImpl *device = This->resource.device;
1008
1009 switch(This->resource.format_desc->format)
1010 {
1011 case WINED3DFMT_P8_UINT:
1012 {
1013 DWORD alpha;
1014
1015 if (primary_render_target_is_p8(device))
1016 alpha = color << 24;
1017 else
1018 alpha = 0xFF000000;
1019
1020 if (This->palette) {
1021 *argb_color = (alpha |
1022 (This->palette->palents[color].peRed << 16) |
1023 (This->palette->palents[color].peGreen << 8) |
1024 (This->palette->palents[color].peBlue));
1025 } else {
1026 *argb_color = alpha;
1027 }
1028 }
1029 break;
1030
1031 case WINED3DFMT_B5G6R5_UNORM:
1032 {
1033 if (color == 0xFFFF) {
1034 *argb_color = 0xFFFFFFFF;
1035 } else {
1036 *argb_color = ((0xFF000000) |
1037 ((color & 0xF800) << 8) |
1038 ((color & 0x07E0) << 5) |
1039 ((color & 0x001F) << 3));
1040 }
1041 }
1042 break;
1043
1044 case WINED3DFMT_B8G8R8_UNORM:
1045 case WINED3DFMT_B8G8R8X8_UNORM:
1046 *argb_color = 0xFF000000 | color;
1047 break;
1048
1049 case WINED3DFMT_B8G8R8A8_UNORM:
1050 *argb_color = color;
1051 break;
1052
1053 default:
1054 ERR("Unhandled conversion from %s to ARGB!\n", debug_d3dformat(This->resource.format_desc->format));
1055 return FALSE;
1056 }
1057 return TRUE;
1058}
1059
1060static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
1061{
1062 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1063 ULONG ref = InterlockedDecrement(&This->resource.ref);
1064 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
1065
1066 if (!ref)
1067 {
1068 surface_cleanup(This);
1069 This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
1070
1071 TRACE("(%p) Released.\n", This);
1072 HeapFree(GetProcessHeap(), 0, This);
1073 }
1074
1075 return ref;
1076}
1077
1078/* ****************************************************
1079 IWineD3DSurface IWineD3DResource parts follow
1080 **************************************************** */
1081
1082void surface_internal_preload(IWineD3DSurface *iface, enum WINED3DSRGB srgb)
1083{
1084 /* TODO: check for locks */
1085 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1086 IWineD3DDeviceImpl *device = This->resource.device;
1087 IWineD3DBaseTexture *baseTexture = NULL;
1088
1089 TRACE("(%p)Checking to see if the container is a base texture\n", This);
1090 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
1091 IWineD3DBaseTextureImpl *tex_impl = (IWineD3DBaseTextureImpl *) baseTexture;
1092 TRACE("Passing to container\n");
1093 tex_impl->baseTexture.internal_preload(baseTexture, srgb);
1094 IWineD3DBaseTexture_Release(baseTexture);
1095 } else {
1096 struct wined3d_context *context = NULL;
1097
1098 TRACE("(%p) : About to load surface\n", This);
1099
1100 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1101
1102 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
1103 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
1104 {
1105 if(palette9_changed(This)) {
1106 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1107 /* TODO: This is not necessarily needed with hw palettized texture support */
1108 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1109 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
1110 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1111 }
1112 }
1113
1114 IWineD3DSurface_LoadTexture(iface, srgb == SRGB_SRGB ? TRUE : FALSE);
1115
1116 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
1117 /* Tell opengl to try and keep this texture in video ram (well mostly) */
1118 GLclampf tmp;
1119 tmp = 0.9f;
1120 ENTER_GL();
1121 glPrioritizeTextures(1, &This->texture_name, &tmp);
1122 LEAVE_GL();
1123 }
1124
1125 if (context) context_release(context);
1126 }
1127}
1128
1129static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
1130 surface_internal_preload(iface, SRGB_ANY);
1131}
1132
1133/* Context activation is done by the caller. */
1134static void surface_remove_pbo(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1135{
1136 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1137 This->resource.allocatedMemory =
1138 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1139
1140 ENTER_GL();
1141 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1142 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
1143 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
1144 checkGLcall("glGetBufferSubDataARB");
1145 GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
1146 checkGLcall("glDeleteBuffersARB");
1147 LEAVE_GL();
1148
1149 This->pbo = 0;
1150 This->Flags &= ~SFLAG_PBO;
1151}
1152
1153BOOL surface_init_sysmem(IWineD3DSurface *iface)
1154{
1155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1156
1157 if(!This->resource.allocatedMemory)
1158 {
1159 This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
1160 if(!This->resource.heapMemory)
1161 {
1162 ERR("Out of memory\n");
1163 return FALSE;
1164 }
1165 This->resource.allocatedMemory =
1166 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1167 }
1168 else
1169 {
1170 memset(This->resource.allocatedMemory, 0, This->resource.size);
1171 }
1172
1173 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1174 return TRUE;
1175}
1176
1177static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
1178 IWineD3DBaseTexture *texture = NULL;
1179 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1180 IWineD3DDeviceImpl *device = This->resource.device;
1181 const struct wined3d_gl_info *gl_info;
1182 renderbuffer_entry_t *entry, *entry2;
1183 struct wined3d_context *context;
1184
1185 TRACE("(%p)\n", iface);
1186
1187 if(This->resource.pool == WINED3DPOOL_DEFAULT) {
1188 /* Default pool resources are supposed to be destroyed before Reset is called.
1189 * Implicit resources stay however. So this means we have an implicit render target
1190 * or depth stencil. The content may be destroyed, but we still have to tear down
1191 * opengl resources, so we cannot leave early.
1192 *
1193 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1194 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1195 * or the depth stencil into an FBO the texture or render buffer will be removed
1196 * and all flags get lost
1197 */
1198 surface_init_sysmem(iface);
1199 } else {
1200 /* Load the surface into system memory */
1201 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1202 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
1203 }
1204 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1205 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
1206 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1207
1208 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1209 gl_info = context->gl_info;
1210
1211 /* Destroy PBOs, but load them into real sysmem before */
1212 if (This->Flags & SFLAG_PBO)
1213 surface_remove_pbo(This, gl_info);
1214
1215 /* Destroy fbo render buffers. This is needed for implicit render targets, for
1216 * all application-created targets the application has to release the surface
1217 * before calling _Reset
1218 */
1219 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
1220 ENTER_GL();
1221 gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1222 LEAVE_GL();
1223 list_remove(&entry->entry);
1224 HeapFree(GetProcessHeap(), 0, entry);
1225 }
1226 list_init(&This->renderbuffers);
1227 This->current_renderbuffer = NULL;
1228
1229 /* If we're in a texture, the texture name belongs to the texture. Otherwise,
1230 * destroy it
1231 */
1232 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
1233 if(!texture) {
1234 ENTER_GL();
1235 glDeleteTextures(1, &This->texture_name);
1236 This->texture_name = 0;
1237 glDeleteTextures(1, &This->texture_name_srgb);
1238 This->texture_name_srgb = 0;
1239 LEAVE_GL();
1240 } else {
1241 IWineD3DBaseTexture_Release(texture);
1242 }
1243
1244 context_release(context);
1245}
1246
1247/* ******************************************************
1248 IWineD3DSurface IWineD3DSurface parts follow
1249 ****************************************************** */
1250
1251/* Read the framebuffer back into the surface */
1252static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
1253{
1254 IWineD3DDeviceImpl *myDevice = This->resource.device;
1255 const struct wined3d_gl_info *gl_info;
1256 struct wined3d_context *context;
1257 BYTE *mem;
1258 GLint fmt;
1259 GLint type;
1260 BYTE *row, *top, *bottom;
1261 int i;
1262 BOOL bpp;
1263 RECT local_rect;
1264 BOOL srcIsUpsideDown;
1265 GLint rowLen = 0;
1266 GLint skipPix = 0;
1267 GLint skipRow = 0;
1268
1269 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1270 static BOOL warned = FALSE;
1271 if(!warned) {
1272 ERR("The application tries to lock the render target, but render target locking is disabled\n");
1273 warned = TRUE;
1274 }
1275 return;
1276 }
1277
1278 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
1279 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
1280 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
1281 * context->last_was_blit set on the unlock.
1282 */
1283 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1284 gl_info = context->gl_info;
1285
1286 ENTER_GL();
1287
1288 /* Select the correct read buffer, and give some debug output.
1289 * There is no need to keep track of the current read buffer or reset it, every part of the code
1290 * that reads sets the read buffer as desired.
1291 */
1292 if (surface_is_offscreen((IWineD3DSurface *) This))
1293 {
1294 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1295 * Read from the back buffer
1296 */
1297 TRACE("Locking offscreen render target\n");
1298 glReadBuffer(myDevice->offscreenBuffer);
1299 srcIsUpsideDown = TRUE;
1300 }
1301 else
1302 {
1303 /* Onscreen surfaces are always part of a swapchain */
1304 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1305 TRACE("Locking %#x buffer\n", buffer);
1306 glReadBuffer(buffer);
1307 checkGLcall("glReadBuffer");
1308 srcIsUpsideDown = FALSE;
1309 }
1310
1311 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1312 if(!rect) {
1313 local_rect.left = 0;
1314 local_rect.top = 0;
1315 local_rect.right = This->currentDesc.Width;
1316 local_rect.bottom = This->currentDesc.Height;
1317 } else {
1318 local_rect = *rect;
1319 }
1320 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1321
1322 switch(This->resource.format_desc->format)
1323 {
1324 case WINED3DFMT_P8_UINT:
1325 {
1326 if(primary_render_target_is_p8(myDevice)) {
1327 /* In case of P8 render targets the index is stored in the alpha component */
1328 fmt = GL_ALPHA;
1329 type = GL_UNSIGNED_BYTE;
1330 mem = dest;
1331 bpp = This->resource.format_desc->byte_count;
1332 } else {
1333 /* GL can't return palettized data, so read ARGB pixels into a
1334 * separate block of memory and convert them into palettized format
1335 * in software. Slow, but if the app means to use palettized render
1336 * targets and locks it...
1337 *
1338 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1339 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1340 * for the color channels when palettizing the colors.
1341 */
1342 fmt = GL_RGB;
1343 type = GL_UNSIGNED_BYTE;
1344 pitch *= 3;
1345 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
1346 if(!mem) {
1347 ERR("Out of memory\n");
1348 LEAVE_GL();
1349 return;
1350 }
1351 bpp = This->resource.format_desc->byte_count * 3;
1352 }
1353 }
1354 break;
1355
1356 default:
1357 mem = dest;
1358 fmt = This->resource.format_desc->glFormat;
1359 type = This->resource.format_desc->glType;
1360 bpp = This->resource.format_desc->byte_count;
1361 }
1362
1363 if(This->Flags & SFLAG_PBO) {
1364 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1365 checkGLcall("glBindBufferARB");
1366 if(mem != NULL) {
1367 ERR("mem not null for pbo -- unexpected\n");
1368 mem = NULL;
1369 }
1370 }
1371
1372 /* Save old pixel store pack state */
1373 glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
1374 checkGLcall("glGetIntegerv");
1375 glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
1376 checkGLcall("glGetIntegerv");
1377 glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
1378 checkGLcall("glGetIntegerv");
1379
1380 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1381 glPixelStorei(GL_PACK_ROW_LENGTH, This->currentDesc.Width);
1382 checkGLcall("glPixelStorei");
1383 glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
1384 checkGLcall("glPixelStorei");
1385 glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
1386 checkGLcall("glPixelStorei");
1387
1388 glReadPixels(local_rect.left, (!srcIsUpsideDown) ? (This->currentDesc.Height - local_rect.bottom) : local_rect.top ,
1389 local_rect.right - local_rect.left,
1390 local_rect.bottom - local_rect.top,
1391 fmt, type, mem);
1392 checkGLcall("glReadPixels");
1393
1394 /* Reset previous pixel store pack state */
1395 glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
1396 checkGLcall("glPixelStorei");
1397 glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
1398 checkGLcall("glPixelStorei");
1399 glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
1400 checkGLcall("glPixelStorei");
1401
1402 if(This->Flags & SFLAG_PBO) {
1403 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1404 checkGLcall("glBindBufferARB");
1405
1406 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1407 * to get a pointer to it and perform the flipping in software. This is a lot
1408 * faster than calling glReadPixels for each line. In case we want more speed
1409 * we should rerender it flipped in a FBO and read the data back from the FBO. */
1410 if(!srcIsUpsideDown) {
1411 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1412 checkGLcall("glBindBufferARB");
1413
1414 mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1415 checkGLcall("glMapBufferARB");
1416 }
1417 }
1418
1419 /* TODO: Merge this with the palettization loop below for P8 targets */
1420 if(!srcIsUpsideDown) {
1421 UINT len, off;
1422 /* glReadPixels returns the image upside down, and there is no way to prevent this.
1423 Flip the lines in software */
1424 len = (local_rect.right - local_rect.left) * bpp;
1425 off = local_rect.left * bpp;
1426
1427 row = HeapAlloc(GetProcessHeap(), 0, len);
1428 if(!row) {
1429 ERR("Out of memory\n");
1430 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
1431 LEAVE_GL();
1432 return;
1433 }
1434
1435 top = mem + pitch * local_rect.top;
1436 bottom = mem + pitch * (local_rect.bottom - 1);
1437 for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
1438 memcpy(row, top + off, len);
1439 memcpy(top + off, bottom + off, len);
1440 memcpy(bottom + off, row, len);
1441 top += pitch;
1442 bottom -= pitch;
1443 }
1444 HeapFree(GetProcessHeap(), 0, row);
1445
1446 /* Unmap the temp PBO buffer */
1447 if(This->Flags & SFLAG_PBO) {
1448 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1449 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1450 }
1451 }
1452
1453 LEAVE_GL();
1454 context_release(context);
1455
1456 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1457 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1458 * the same color but we have no choice.
1459 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1460 */
1461 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(myDevice))
1462 {
1463 const PALETTEENTRY *pal = NULL;
1464 DWORD width = pitch / 3;
1465 int x, y, c;
1466
1467 if(This->palette) {
1468 pal = This->palette->palents;
1469 } else {
1470 ERR("Palette is missing, cannot perform inverse palette lookup\n");
1471 HeapFree(GetProcessHeap(), 0, mem);
1472 return ;
1473 }
1474
1475 for(y = local_rect.top; y < local_rect.bottom; y++) {
1476 for(x = local_rect.left; x < local_rect.right; x++) {
1477 /* start lines pixels */
1478 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
1479 const BYTE *green = blue + 1;
1480 const BYTE *red = green + 1;
1481
1482 for(c = 0; c < 256; c++) {
1483 if(*red == pal[c].peRed &&
1484 *green == pal[c].peGreen &&
1485 *blue == pal[c].peBlue)
1486 {
1487 *((BYTE *) dest + y * width + x) = c;
1488 break;
1489 }
1490 }
1491 }
1492 }
1493 HeapFree(GetProcessHeap(), 0, mem);
1494 }
1495}
1496
1497/* Read the framebuffer contents into a texture */
1498static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
1499{
1500 IWineD3DDeviceImpl *device = This->resource.device;
1501 const struct wined3d_gl_info *gl_info;
1502 struct wined3d_context *context;
1503 GLint prevRead;
1504 BOOL alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1505
1506 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1507 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1508 * states in the stateblock, and no driver was found yet that had bugs in that regard.
1509 */
1510 context = context_acquire(device, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD);
1511 gl_info = context->gl_info;
1512
1513 surface_bind_and_dirtify(This, srgb);
1514
1515 ENTER_GL();
1516 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1517 LEAVE_GL();
1518
1519 /* Select the correct read buffer, and give some debug output.
1520 * There is no need to keep track of the current read buffer or reset it, every part of the code
1521 * that reads sets the read buffer as desired.
1522 */
1523 if (!surface_is_offscreen((IWineD3DSurface *)This))
1524 {
1525 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1526 TRACE("Locking %#x buffer\n", buffer);
1527
1528 ENTER_GL();
1529 glReadBuffer(buffer);
1530 checkGLcall("glReadBuffer");
1531 LEAVE_GL();
1532 }
1533 else
1534 {
1535 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1536 * Read from the back buffer
1537 */
1538 TRACE("Locking offscreen render target\n");
1539 ENTER_GL();
1540 glReadBuffer(device->offscreenBuffer);
1541 checkGLcall("glReadBuffer");
1542 LEAVE_GL();
1543 }
1544
1545 if (!(This->Flags & alloc_flag))
1546 {
1547 surface_allocate_surface(This, gl_info, This->resource.format_desc, srgb);
1548 This->Flags |= alloc_flag;
1549 }
1550
1551 ENTER_GL();
1552 /* If !SrcIsUpsideDown we should flip the surface.
1553 * This can be done using glCopyTexSubImage2D but this
1554 * is VERY slow, so don't do that. We should prevent
1555 * this code from getting called in such cases or perhaps
1556 * we can use FBOs */
1557
1558 glCopyTexSubImage2D(This->texture_target, This->texture_level,
1559 0, 0, 0, 0, This->currentDesc.Width, This->currentDesc.Height);
1560 checkGLcall("glCopyTexSubImage2D");
1561
1562 glReadBuffer(prevRead);
1563 checkGLcall("glReadBuffer");
1564
1565 LEAVE_GL();
1566
1567 context_release(context);
1568
1569 TRACE("Updated target %d\n", This->texture_target);
1570}
1571
1572/* Context activation is done by the caller. */
1573void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
1574{
1575 DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1576 CONVERT_TYPES convert;
1577 struct wined3d_format_desc desc;
1578
1579 if (surface->Flags & alloc_flag) return;
1580
1581 d3dfmt_get_conv(surface, TRUE, TRUE, &desc, &convert);
1582 if(convert != NO_CONVERSION) surface->Flags |= SFLAG_CONVERTED;
1583 else surface->Flags &= ~SFLAG_CONVERTED;
1584
1585 surface_bind_and_dirtify(surface, srgb);
1586 surface_allocate_surface(surface, gl_info, &desc, srgb);
1587 surface->Flags |= alloc_flag;
1588}
1589
1590static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
1591{
1592 IWineD3DDeviceImpl *device = This->resource.device;
1593 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1594
1595 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1596 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1597 * changed
1598 */
1599 if(!(This->Flags & SFLAG_DYNLOCK)) {
1600 This->lockCount++;
1601 /* MAXLOCKCOUNT is defined in wined3d_private.h */
1602 if(This->lockCount > MAXLOCKCOUNT) {
1603 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1604 This->Flags |= SFLAG_DYNLOCK;
1605 }
1606 }
1607
1608 /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1609 * Also don't create a PBO for systemmem surfaces.
1610 */
1611 if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->Flags & SFLAG_DYNLOCK)
1612 && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
1613 && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
1614 {
1615 GLenum error;
1616 struct wined3d_context *context;
1617
1618 context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1619 ENTER_GL();
1620
1621 GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
1622 error = glGetError();
1623 if(This->pbo == 0 || error != GL_NO_ERROR) {
1624 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1625 }
1626
1627 TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
1628
1629 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1630 checkGLcall("glBindBufferARB");
1631
1632 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
1633 checkGLcall("glBufferDataARB");
1634
1635 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1636 checkGLcall("glBindBufferARB");
1637
1638 /* We don't need the system memory anymore and we can't even use it for PBOs */
1639 if(!(This->Flags & SFLAG_CLIENT)) {
1640 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
1641 This->resource.heapMemory = NULL;
1642 }
1643 This->resource.allocatedMemory = NULL;
1644 This->Flags |= SFLAG_PBO;
1645 LEAVE_GL();
1646 context_release(context);
1647 }
1648 else if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO))
1649 {
1650 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1651 * or a pbo to map
1652 */
1653 if(!This->resource.heapMemory) {
1654 This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1655 }
1656 This->resource.allocatedMemory =
1657 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1658 if(This->Flags & SFLAG_INSYSMEM) {
1659 ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1660 }
1661 }
1662}
1663
1664static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
1665 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1666 IWineD3DDeviceImpl *myDevice = This->resource.device;
1667 const RECT *pass_rect = pRect;
1668
1669 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1670
1671 /* This is also done in the base class, but we have to verify this before loading any data from
1672 * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1673 * may interfere, and all other bad things may happen
1674 */
1675 if (This->Flags & SFLAG_LOCKED) {
1676 WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1677 return WINED3DERR_INVALIDCALL;
1678 }
1679 This->Flags |= SFLAG_LOCKED;
1680
1681 if (!(This->Flags & SFLAG_LOCKABLE))
1682 {
1683 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1684 }
1685
1686 if (Flags & WINED3DLOCK_DISCARD) {
1687 /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1688 TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1689 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1690 This->Flags |= SFLAG_INSYSMEM;
1691 goto lock_end;
1692 }
1693
1694 if (This->Flags & SFLAG_INSYSMEM) {
1695 TRACE("Local copy is up to date, not downloading data\n");
1696 surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1697 goto lock_end;
1698 }
1699
1700 /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1701 * the full surface. Most callers don't need that, so do it here. */
1702 if (pRect && pRect->top == 0 && pRect->left == 0
1703 && pRect->right == This->currentDesc.Width
1704 && pRect->bottom == This->currentDesc.Height)
1705 {
1706 pass_rect = NULL;
1707 }
1708
1709 if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1710 && ((This->Flags & SFLAG_SWAPCHAIN) || iface == myDevice->render_targets[0])))
1711 {
1712 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pass_rect);
1713 }
1714
1715lock_end:
1716 if (This->Flags & SFLAG_PBO)
1717 {
1718 const struct wined3d_gl_info *gl_info;
1719 struct wined3d_context *context;
1720
1721 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1722 gl_info = context->gl_info;
1723
1724 ENTER_GL();
1725 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1726 checkGLcall("glBindBufferARB");
1727
1728 /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1729 if(This->resource.allocatedMemory) {
1730 ERR("The surface already has PBO memory allocated!\n");
1731 }
1732
1733 This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1734 checkGLcall("glMapBufferARB");
1735
1736 /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1737 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1738 checkGLcall("glBindBufferARB");
1739
1740 LEAVE_GL();
1741 context_release(context);
1742 }
1743
1744 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
1745 /* Don't dirtify */
1746 } else {
1747 IWineD3DBaseTexture *pBaseTexture;
1748 /**
1749 * Dirtify on lock
1750 * as seen in msdn docs
1751 */
1752 surface_add_dirty_rect(iface, pRect);
1753
1754 /** Dirtify Container if needed */
1755 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
1756 TRACE("Making container dirty\n");
1757 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
1758 IWineD3DBaseTexture_Release(pBaseTexture);
1759 } else {
1760 TRACE("Surface is standalone, no need to dirty the container\n");
1761 }
1762 }
1763
1764 return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
1765}
1766
1767static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
1768 GLint prev_store;
1769 GLint prev_rasterpos[4];
1770 GLint skipBytes = 0;
1771 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
1772 IWineD3DDeviceImpl *myDevice = This->resource.device;
1773 const struct wined3d_gl_info *gl_info;
1774 struct wined3d_context *context;
1775
1776 /* Activate the correct context for the render target */
1777 context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1778 gl_info = context->gl_info;
1779
1780 ENTER_GL();
1781
1782 if (!surface_is_offscreen((IWineD3DSurface *)This))
1783 {
1784 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1785 TRACE("Unlocking %#x buffer.\n", buffer);
1786 context_set_draw_buffer(context, buffer);
1787 }
1788 else
1789 {
1790 /* Primary offscreen render target */
1791 TRACE("Offscreen render target.\n");
1792 context_set_draw_buffer(context, myDevice->offscreenBuffer);
1793 }
1794
1795 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1796 checkGLcall("glGetIntegerv");
1797 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1798 checkGLcall("glGetIntegerv");
1799 glPixelZoom(1.0f, -1.0f);
1800 checkGLcall("glPixelZoom");
1801
1802 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1803 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1804 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1805
1806 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1807 checkGLcall("glRasterPos3i");
1808
1809 /* Some drivers(radeon dri, others?) don't like exceptions during
1810 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1811 * after ReleaseDC. Reading it will cause an exception, which x11drv will
1812 * catch to put the dib section in InSync mode, which leads to a crash
1813 * and a blocked x server on my radeon card.
1814 *
1815 * The following lines read the dib section so it is put in InSync mode
1816 * before glDrawPixels is called and the crash is prevented. There won't
1817 * be any interfering gdi accesses, because UnlockRect is called from
1818 * ReleaseDC, and the app won't use the dc any more afterwards.
1819 */
1820 if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1821 volatile BYTE read;
1822 read = This->resource.allocatedMemory[0];
1823 }
1824
1825 if(This->Flags & SFLAG_PBO) {
1826 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1827 checkGLcall("glBindBufferARB");
1828 }
1829
1830 /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1831 if(This->Flags & SFLAG_LOCKED) {
1832 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1833 (This->lockedRect.bottom - This->lockedRect.top)-1,
1834 fmt, type,
1835 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1836 checkGLcall("glDrawPixels");
1837 } else {
1838 glDrawPixels(This->currentDesc.Width,
1839 This->currentDesc.Height,
1840 fmt, type, mem);
1841 checkGLcall("glDrawPixels");
1842 }
1843
1844 if(This->Flags & SFLAG_PBO) {
1845 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1846 checkGLcall("glBindBufferARB");
1847 }
1848
1849 glPixelZoom(1.0f, 1.0f);
1850 checkGLcall("glPixelZoom");
1851
1852 glRasterPos3iv(&prev_rasterpos[0]);
1853 checkGLcall("glRasterPos3iv");
1854
1855 /* Reset to previous pack row length */
1856 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1857 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1858
1859 LEAVE_GL();
1860 context_release(context);
1861}
1862
1863static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1864 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1865 IWineD3DDeviceImpl *myDevice = This->resource.device;
1866 BOOL fullsurface;
1867
1868 if (!(This->Flags & SFLAG_LOCKED)) {
1869 WARN("trying to Unlock an unlocked surf@%p\n", This);
1870 return WINEDDERR_NOTLOCKED;
1871 }
1872
1873 if (This->Flags & SFLAG_PBO)
1874 {
1875 const struct wined3d_gl_info *gl_info;
1876 struct wined3d_context *context;
1877
1878 TRACE("Freeing PBO memory\n");
1879
1880 context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1881 gl_info = context->gl_info;
1882
1883 ENTER_GL();
1884 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1885 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1886 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1887 checkGLcall("glUnmapBufferARB");
1888 LEAVE_GL();
1889 context_release(context);
1890
1891 This->resource.allocatedMemory = NULL;
1892 }
1893
1894 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1895
1896 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1897 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1898 goto unlock_end;
1899 }
1900
1901 if ((This->Flags & SFLAG_SWAPCHAIN) || (myDevice->render_targets && iface == myDevice->render_targets[0]))
1902 {
1903 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1904 static BOOL warned = FALSE;
1905 if(!warned) {
1906 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1907 warned = TRUE;
1908 }
1909 goto unlock_end;
1910 }
1911
1912 if(This->dirtyRect.left == 0 &&
1913 This->dirtyRect.top == 0 &&
1914 This->dirtyRect.right == This->currentDesc.Width &&
1915 This->dirtyRect.bottom == This->currentDesc.Height) {
1916 fullsurface = TRUE;
1917 } else {
1918 /* TODO: Proper partial rectangle tracking */
1919 fullsurface = FALSE;
1920 This->Flags |= SFLAG_INSYSMEM;
1921 }
1922
1923 switch(wined3d_settings.rendertargetlock_mode) {
1924 case RTL_READTEX:
1925 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1926 /* drop through */
1927
1928 case RTL_READDRAW:
1929 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1930 break;
1931 }
1932
1933 if(!fullsurface) {
1934 /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1935 * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1936 * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1937 * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1938 * not fully up to date because only a subrectangle was read in LockRect.
1939 */
1940 This->Flags &= ~SFLAG_INSYSMEM;
1941 This->Flags |= SFLAG_INDRAWABLE;
1942 }
1943
1944 This->dirtyRect.left = This->currentDesc.Width;
1945 This->dirtyRect.top = This->currentDesc.Height;
1946 This->dirtyRect.right = 0;
1947 This->dirtyRect.bottom = 0;
1948 } else if(iface == myDevice->stencilBufferTarget) {
1949 FIXME("Depth Stencil buffer locking is not implemented\n");
1950 } else {
1951 /* The rest should be a normal texture */
1952 IWineD3DBaseTextureImpl *impl;
1953 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1954 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1955 * states need resetting
1956 */
1957 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1958 if(impl->baseTexture.bindCount) {
1959 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1960 }
1961 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1962 }
1963 }
1964
1965 unlock_end:
1966 This->Flags &= ~SFLAG_LOCKED;
1967 memset(&This->lockedRect, 0, sizeof(RECT));
1968
1969 /* Overlays have to be redrawn manually after changes with the GL implementation */
1970 if(This->overlay_dest) {
1971 IWineD3DSurface_DrawOverlay(iface);
1972 }
1973 return WINED3D_OK;
1974}
1975
1976static void surface_release_client_storage(IWineD3DSurface *iface)
1977{
1978 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1979 struct wined3d_context *context;
1980
1981 context = context_acquire(This->resource.device, NULL, CTXUSAGE_RESOURCELOAD);
1982
1983 ENTER_GL();
1984 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1985 if(This->texture_name)
1986 {
1987 surface_bind_and_dirtify(This, FALSE);
1988 glTexImage2D(This->texture_target, This->texture_level,
1989 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1990 }
1991 if(This->texture_name_srgb)
1992 {
1993 surface_bind_and_dirtify(This, TRUE);
1994 glTexImage2D(This->texture_target, This->texture_level,
1995 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1996 }
1997 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1998
1999 LEAVE_GL();
2000 context_release(context);
2001
2002 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
2003 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
2004 surface_force_reload(iface);
2005}
2006
2007static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
2008{
2009 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2010 WINED3DLOCKED_RECT lock;
2011 HRESULT hr;
2012 RGBQUAD col[256];
2013
2014 TRACE("(%p)->(%p)\n",This,pHDC);
2015
2016 if(This->Flags & SFLAG_USERPTR) {
2017 ERR("Not supported on surfaces with an application-provided surfaces\n");
2018 return WINEDDERR_NODC;
2019 }
2020
2021 /* Give more detailed info for ddraw */
2022 if (This->Flags & SFLAG_DCINUSE)
2023 return WINEDDERR_DCALREADYCREATED;
2024
2025 /* Can't GetDC if the surface is locked */
2026 if (This->Flags & SFLAG_LOCKED)
2027 return WINED3DERR_INVALIDCALL;
2028
2029 memset(&lock, 0, sizeof(lock)); /* To be sure */
2030
2031 /* Create a DIB section if there isn't a hdc yet */
2032 if(!This->hDC) {
2033 if(This->Flags & SFLAG_CLIENT) {
2034 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2035 surface_release_client_storage(iface);
2036 }
2037 hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
2038 if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
2039
2040 /* Use the dib section from now on if we are not using a PBO */
2041 if(!(This->Flags & SFLAG_PBO))
2042 This->resource.allocatedMemory = This->dib.bitmap_data;
2043 }
2044
2045 /* Lock the surface */
2046 hr = IWineD3DSurface_LockRect(iface,
2047 &lock,
2048 NULL,
2049 0);
2050
2051 if(This->Flags & SFLAG_PBO) {
2052 /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
2053 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
2054 }
2055
2056 if(FAILED(hr)) {
2057 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
2058 /* keep the dib section */
2059 return hr;
2060 }
2061
2062 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
2063 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
2064 {
2065 /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
2066 D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
2067 unsigned int n;
2068 const PALETTEENTRY *pal = NULL;
2069
2070 if(This->palette) {
2071 pal = This->palette->palents;
2072 } else {
2073 IWineD3DSurfaceImpl *dds_primary;
2074 IWineD3DSwapChainImpl *swapchain;
2075 swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
2076 dds_primary = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
2077 if (dds_primary && dds_primary->palette)
2078 pal = dds_primary->palette->palents;
2079 }
2080
2081 if (pal) {
2082 for (n=0; n<256; n++) {
2083 col[n].rgbRed = pal[n].peRed;
2084 col[n].rgbGreen = pal[n].peGreen;
2085 col[n].rgbBlue = pal[n].peBlue;
2086 col[n].rgbReserved = 0;
2087 }
2088 SetDIBColorTable(This->hDC, 0, 256, col);
2089 }
2090 }
2091
2092 *pHDC = This->hDC;
2093 TRACE("returning %p\n",*pHDC);
2094 This->Flags |= SFLAG_DCINUSE;
2095
2096 return WINED3D_OK;
2097}
2098
2099static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
2100{
2101 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2102
2103 TRACE("(%p)->(%p)\n",This,hDC);
2104
2105 if (!(This->Flags & SFLAG_DCINUSE))
2106 return WINEDDERR_NODC;
2107
2108 if (This->hDC !=hDC) {
2109 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
2110 return WINEDDERR_NODC;
2111 }
2112
2113 if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
2114 /* Copy the contents of the DIB over to the PBO */
2115 memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
2116 }
2117
2118 /* we locked first, so unlock now */
2119 IWineD3DSurface_UnlockRect(iface);
2120
2121 This->Flags &= ~SFLAG_DCINUSE;
2122
2123 return WINED3D_OK;
2124}
2125
2126/* ******************************************************
2127 IWineD3DSurface Internal (No mapping to directx api) parts follow
2128 ****************************************************** */
2129
2130HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, struct wined3d_format_desc *desc, CONVERT_TYPES *convert)
2131{
2132 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
2133 IWineD3DDeviceImpl *device = This->resource.device;
2134 BOOL blit_supported = FALSE;
2135 RECT rect = {0, 0, This->pow2Width, This->pow2Height};
2136
2137 /* Copy the default values from the surface. Below we might perform fixups */
2138 /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2139 *desc = *This->resource.format_desc;
2140 *convert = NO_CONVERSION;
2141
2142 /* Ok, now look if we have to do any conversion */
2143 switch(This->resource.format_desc->format)
2144 {
2145 case WINED3DFMT_P8_UINT:
2146 /* ****************
2147 Paletted Texture
2148 **************** */
2149
2150 blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, BLIT_OP_BLIT,
2151 &rect, This->resource.usage, This->resource.pool,
2152 This->resource.format_desc, &rect, This->resource.usage,
2153 This->resource.pool, This->resource.format_desc);
2154
2155 /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2156 * texturing. Further also use conversion in case of color keying.
2157 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2158 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2159 * conflicts with this.
2160 */
2161 if (!((blit_supported && device->render_targets && This == (IWineD3DSurfaceImpl*)device->render_targets[0]))
2162 || colorkey_active || !use_texturing)
2163 {
2164 desc->glFormat = GL_RGBA;
2165 desc->glInternal = GL_RGBA;
2166 desc->glType = GL_UNSIGNED_BYTE;
2167 desc->conv_byte_count = 4;
2168 if(colorkey_active) {
2169 *convert = CONVERT_PALETTED_CK;
2170 } else {
2171 *convert = CONVERT_PALETTED;
2172 }
2173 }
2174 break;
2175
2176 case WINED3DFMT_B2G3R3_UNORM:
2177 /* **********************
2178 GL_UNSIGNED_BYTE_3_3_2
2179 ********************** */
2180 if (colorkey_active) {
2181 /* This texture format will never be used.. So do not care about color keying
2182 up until the point in time it will be needed :-) */
2183 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2184 }
2185 break;
2186
2187 case WINED3DFMT_B5G6R5_UNORM:
2188 if (colorkey_active) {
2189 *convert = CONVERT_CK_565;
2190 desc->glFormat = GL_RGBA;
2191 desc->glInternal = GL_RGB5_A1;
2192 desc->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2193 desc->conv_byte_count = 2;
2194 }
2195 break;
2196
2197 case WINED3DFMT_B5G5R5X1_UNORM:
2198 if (colorkey_active) {
2199 *convert = CONVERT_CK_5551;
2200 desc->glFormat = GL_BGRA;
2201 desc->glInternal = GL_RGB5_A1;
2202 desc->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2203 desc->conv_byte_count = 2;
2204 }
2205 break;
2206
2207 case WINED3DFMT_B8G8R8_UNORM:
2208 if (colorkey_active) {
2209 *convert = CONVERT_CK_RGB24;
2210 desc->glFormat = GL_RGBA;
2211 desc->glInternal = GL_RGBA8;
2212 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2213 desc->conv_byte_count = 4;
2214 }
2215 break;
2216
2217 case WINED3DFMT_B8G8R8X8_UNORM:
2218 if (colorkey_active) {
2219 *convert = CONVERT_RGB32_888;
2220 desc->glFormat = GL_RGBA;
2221 desc->glInternal = GL_RGBA8;
2222 desc->glType = GL_UNSIGNED_INT_8_8_8_8;
2223 desc->conv_byte_count = 4;
2224 }
2225 break;
2226
2227 default:
2228 break;
2229 }
2230
2231 return WINED3D_OK;
2232}
2233
2234void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2235{
2236 IWineD3DDeviceImpl *device = This->resource.device;
2237 IWineD3DPaletteImpl *pal = This->palette;
2238 BOOL index_in_alpha = FALSE;
2239 unsigned int i;
2240
2241 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2242 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2243 * is slow. Further RGB->P8 conversion is not possible because palettes can have
2244 * duplicate entries. Store the color key in the unused alpha component to speed the
2245 * download up and to make conversion unneeded. */
2246 index_in_alpha = primary_render_target_is_p8(device);
2247
2248 if (!pal)
2249 {
2250 UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2251
2252 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2253 if (dxVersion <= 7)
2254 {
2255 ERR("This code should never get entered for DirectDraw!, expect problems\n");
2256 if (index_in_alpha)
2257 {
2258 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2259 * there's no palette at this time. */
2260 for (i = 0; i < 256; i++) table[i][3] = i;
2261 }
2262 }
2263 else
2264 {
2265 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2266 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2267 * capability flag is present (wine does advertise this capability) */
2268 for (i = 0; i < 256; ++i)
2269 {
2270 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2271 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2272 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2273 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2274 }
2275 }
2276 }
2277 else
2278 {
2279 TRACE("Using surface palette %p\n", pal);
2280 /* Get the surface's palette */
2281 for (i = 0; i < 256; ++i)
2282 {
2283 table[i][0] = pal->palents[i].peRed;
2284 table[i][1] = pal->palents[i].peGreen;
2285 table[i][2] = pal->palents[i].peBlue;
2286
2287 /* When index_in_alpha is set the palette index is stored in the
2288 * alpha component. In case of a readback we can then read
2289 * GL_ALPHA. Color keying is handled in BltOverride using a
2290 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2291 * color key itself is passed to glAlphaFunc in other cases the
2292 * alpha component of pixels that should be masked away is set to 0. */
2293 if (index_in_alpha)
2294 {
2295 table[i][3] = i;
2296 }
2297 else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2298 && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2299 {
2300 table[i][3] = 0x00;
2301 }
2302 else if(pal->Flags & WINEDDPCAPS_ALPHA)
2303 {
2304 table[i][3] = pal->palents[i].peFlags;
2305 }
2306 else
2307 {
2308 table[i][3] = 0xFF;
2309 }
2310 }
2311 }
2312}
2313
2314static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2315 UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2316{
2317 const BYTE *source;
2318 BYTE *dest;
2319 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2320
2321 switch (convert) {
2322 case NO_CONVERSION:
2323 {
2324 memcpy(dst, src, pitch * height);
2325 break;
2326 }
2327 case CONVERT_PALETTED:
2328 case CONVERT_PALETTED_CK:
2329 {
2330 IWineD3DPaletteImpl* pal = This->palette;
2331 BYTE table[256][4];
2332 unsigned int x, y;
2333
2334 if( pal == NULL) {
2335 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2336 }
2337
2338 d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2339
2340 for (y = 0; y < height; y++)
2341 {
2342 source = src + pitch * y;
2343 dest = dst + outpitch * y;
2344 /* This is an 1 bpp format, using the width here is fine */
2345 for (x = 0; x < width; x++) {
2346 BYTE color = *source++;
2347 *dest++ = table[color][0];
2348 *dest++ = table[color][1];
2349 *dest++ = table[color][2];
2350 *dest++ = table[color][3];
2351 }
2352 }
2353 }
2354 break;
2355
2356 case CONVERT_CK_565:
2357 {
2358 /* Converting the 565 format in 5551 packed to emulate color-keying.
2359
2360 Note : in all these conversion, it would be best to average the averaging
2361 pixels to get the color of the pixel that will be color-keyed to
2362 prevent 'color bleeding'. This will be done later on if ever it is
2363 too visible.
2364
2365 Note2: Nvidia documents say that their driver does not support alpha + color keying
2366 on the same surface and disables color keying in such a case
2367 */
2368 unsigned int x, y;
2369 const WORD *Source;
2370 WORD *Dest;
2371
2372 TRACE("Color keyed 565\n");
2373
2374 for (y = 0; y < height; y++) {
2375 Source = (const WORD *)(src + y * pitch);
2376 Dest = (WORD *) (dst + y * outpitch);
2377 for (x = 0; x < width; x++ ) {
2378 WORD color = *Source++;
2379 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2380 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2381 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2382 *Dest |= 0x0001;
2383 }
2384 Dest++;
2385 }
2386 }
2387 }
2388 break;
2389
2390 case CONVERT_CK_5551:
2391 {
2392 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2393 unsigned int x, y;
2394 const WORD *Source;
2395 WORD *Dest;
2396 TRACE("Color keyed 5551\n");
2397 for (y = 0; y < height; y++) {
2398 Source = (const WORD *)(src + y * pitch);
2399 Dest = (WORD *) (dst + y * outpitch);
2400 for (x = 0; x < width; x++ ) {
2401 WORD color = *Source++;
2402 *Dest = color;
2403 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2404 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2405 *Dest |= (1 << 15);
2406 }
2407 else {
2408 *Dest &= ~(1 << 15);
2409 }
2410 Dest++;
2411 }
2412 }
2413 }
2414 break;
2415
2416 case CONVERT_CK_RGB24:
2417 {
2418 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2419 unsigned int x, y;
2420 for (y = 0; y < height; y++)
2421 {
2422 source = src + pitch * y;
2423 dest = dst + outpitch * y;
2424 for (x = 0; x < width; x++) {
2425 DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2426 DWORD dstcolor = color << 8;
2427 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2428 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2429 dstcolor |= 0xff;
2430 }
2431 *(DWORD*)dest = dstcolor;
2432 source += 3;
2433 dest += 4;
2434 }
2435 }
2436 }
2437 break;
2438
2439 case CONVERT_RGB32_888:
2440 {
2441 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2442 unsigned int x, y;
2443 for (y = 0; y < height; y++)
2444 {
2445 source = src + pitch * y;
2446 dest = dst + outpitch * y;
2447 for (x = 0; x < width; x++) {
2448 DWORD color = 0xffffff & *(const DWORD*)source;
2449 DWORD dstcolor = color << 8;
2450 if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2451 (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2452 dstcolor |= 0xff;
2453 }
2454 *(DWORD*)dest = dstcolor;
2455 source += 4;
2456 dest += 4;
2457 }
2458 }
2459 }
2460 break;
2461
2462 default:
2463 ERR("Unsupported conversion type %#x.\n", convert);
2464 }
2465 return WINED3D_OK;
2466}
2467
2468BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2469{
2470 IWineD3DDeviceImpl *device = This->resource.device;
2471
2472 if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2473 && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2474 {
2475 /* If a ddraw-style palette is attached assume no d3d9 palette change.
2476 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2477 */
2478 return FALSE;
2479 }
2480
2481 if (This->palette9)
2482 {
2483 if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2484 {
2485 return FALSE;
2486 }
2487 } else {
2488 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2489 }
2490 memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2491 return TRUE;
2492}
2493
2494static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2495 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2496 DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2497
2498 if (!(This->Flags & flag)) {
2499 TRACE("Reloading because surface is dirty\n");
2500 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2501 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2502 /* Reload: vice versa OR */
2503 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2504 /* Also reload: Color key is active AND the color key has changed */
2505 ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2506 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2507 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2508 TRACE("Reloading because of color keying\n");
2509 /* To perform the color key conversion we need a sysmem copy of
2510 * the surface. Make sure we have it
2511 */
2512
2513 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2514 /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2515 /* TODO: This is not necessarily needed with hw palettized texture support */
2516 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2517 } else {
2518 TRACE("surface is already in texture\n");
2519 return WINED3D_OK;
2520 }
2521
2522 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2523 * These resources are not bound by device size or format restrictions. Because of this,
2524 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2525 * However, these resources can always be created, locked, and copied.
2526 */
2527 if (This->resource.pool == WINED3DPOOL_SCRATCH )
2528 {
2529 FIXME("(%p) Operation not supported for scratch textures\n",This);
2530 return WINED3DERR_INVALIDCALL;
2531 }
2532
2533 IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */);
2534
2535#if 0
2536 {
2537 static unsigned int gen = 0;
2538 char buffer[4096];
2539 ++gen;
2540 if ((gen % 10) == 0) {
2541 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm",
2542 This, This->texture_target, This->texture_level, gen);
2543 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2544 }
2545 /*
2546 * debugging crash code
2547 if (gen == 250) {
2548 void** test = NULL;
2549 *test = 0;
2550 }
2551 */
2552 }
2553#endif
2554
2555 if (!(This->Flags & SFLAG_DONOTFREE)) {
2556 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2557 This->resource.allocatedMemory = NULL;
2558 This->resource.heapMemory = NULL;
2559 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2560 }
2561
2562 return WINED3D_OK;
2563}
2564
2565/* Context activation is done by the caller. */
2566static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2567 /* TODO: check for locks */
2568 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2569 IWineD3DBaseTexture *baseTexture = NULL;
2570
2571 TRACE("(%p)Checking to see if the container is a base texture\n", This);
2572 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2573 TRACE("Passing to container\n");
2574 IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2575 IWineD3DBaseTexture_Release(baseTexture);
2576 }
2577 else
2578 {
2579 GLuint *name;
2580
2581 TRACE("(%p) : Binding surface\n", This);
2582
2583 name = srgb ? &This->texture_name_srgb : &This->texture_name;
2584
2585 ENTER_GL();
2586
2587 if (!This->texture_level)
2588 {
2589 if (!*name) {
2590 glGenTextures(1, name);
2591 checkGLcall("glGenTextures");
2592 TRACE("Surface %p given name %d\n", This, *name);
2593
2594 glBindTexture(This->texture_target, *name);
2595 checkGLcall("glBindTexture");
2596 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2597 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2598 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2599 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2600 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2601 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2602 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2603 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2604 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2605 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2606 }
2607 /* This is where we should be reducing the amount of GLMemoryUsed */
2608 } else if (*name) {
2609 /* Mipmap surfaces should have a base texture container */
2610 ERR("Mipmap surface has a glTexture bound to it!\n");
2611 }
2612
2613 glBindTexture(This->texture_target, *name);
2614 checkGLcall("glBindTexture");
2615
2616 LEAVE_GL();
2617 }
2618}
2619
2620#include <errno.h>
2621#include <stdio.h>
2622static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename)
2623{
2624 FILE* f = NULL;
2625 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2626 char *allocatedMemory;
2627 const char *textureRow;
2628 IWineD3DSwapChain *swapChain = NULL;
2629 int width, height, i, y;
2630 GLuint tmpTexture = 0;
2631 DWORD color;
2632 /*FIXME:
2633 Textures may not be stored in ->allocatedgMemory and a GlTexture
2634 so we should lock the surface before saving a snapshot, or at least check that
2635 */
2636 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2637 by calling GetTexImage and in compressed form by calling
2638 GetCompressedTexImageARB. Queried compressed images can be saved and
2639 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2640 texture images do not need to be processed by the GL and should
2641 significantly improve texture loading performance relative to uncompressed
2642 images. */
2643
2644/* Setup the width and height to be the internal texture width and height. */
2645 width = This->pow2Width;
2646 height = This->pow2Height;
2647/* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2648 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2649
2650 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2651 /* if were not a real texture then read the back buffer into a real texture */
2652 /* we don't want to interfere with the back buffer so read the data into a temporary
2653 * texture and then save the data out of the temporary texture
2654 */
2655 GLint prevRead;
2656 ENTER_GL();
2657 TRACE("(%p) Reading render target into texture\n", This);
2658
2659 glGenTextures(1, &tmpTexture);
2660 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2661
2662 glTexImage2D(GL_TEXTURE_2D,
2663 0,
2664 GL_RGBA,
2665 width,
2666 height,
2667 0/*border*/,
2668 GL_RGBA,
2669 GL_UNSIGNED_INT_8_8_8_8_REV,
2670 NULL);
2671
2672 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2673 checkGLcall("glGetIntegerv");
2674 glReadBuffer(swapChain ? GL_BACK : This->resource.device->offscreenBuffer);
2675 checkGLcall("glReadBuffer");
2676 glCopyTexImage2D(GL_TEXTURE_2D,
2677 0,
2678 GL_RGBA,
2679 0,
2680 0,
2681 width,
2682 height,
2683 0);
2684
2685 checkGLcall("glCopyTexImage2D");
2686 glReadBuffer(prevRead);
2687 LEAVE_GL();
2688
2689 } else { /* bind the real texture, and make sure it up to date */
2690 surface_internal_preload(iface, SRGB_RGB);
2691 surface_bind_and_dirtify(This, FALSE);
2692 }
2693 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2694 ENTER_GL();
2695 FIXME("Saving texture level %d width %d height %d\n", This->texture_level, width, height);
2696 glGetTexImage(GL_TEXTURE_2D, This->texture_level, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, allocatedMemory);
2697 checkGLcall("glGetTexImage");
2698 if (tmpTexture) {
2699 glBindTexture(GL_TEXTURE_2D, 0);
2700 glDeleteTextures(1, &tmpTexture);
2701 }
2702 LEAVE_GL();
2703
2704 f = fopen(filename, "w+");
2705 if (NULL == f) {
2706 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2707 return WINED3DERR_INVALIDCALL;
2708 }
2709/* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2710 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format_desc->format));
2711/* TGA header */
2712 fputc(0,f);
2713 fputc(0,f);
2714 fputc(2,f);
2715 fputc(0,f);
2716 fputc(0,f);
2717 fputc(0,f);
2718 fputc(0,f);
2719 fputc(0,f);
2720 fputc(0,f);
2721 fputc(0,f);
2722 fputc(0,f);
2723 fputc(0,f);
2724/* short width*/
2725 fwrite(&width,2,1,f);
2726/* short height */
2727 fwrite(&height,2,1,f);
2728/* format rgba */
2729 fputc(0x20,f);
2730 fputc(0x28,f);
2731/* raw data */
2732 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up */
2733 if(swapChain)
2734 textureRow = allocatedMemory + (width * (height - 1) *4);
2735 else
2736 textureRow = allocatedMemory;
2737 for (y = 0 ; y < height; y++) {
2738 for (i = 0; i < width; i++) {
2739 color = *((const DWORD*)textureRow);
2740 fputc((color >> 16) & 0xFF, f); /* B */
2741 fputc((color >> 8) & 0xFF, f); /* G */
2742 fputc((color >> 0) & 0xFF, f); /* R */
2743 fputc((color >> 24) & 0xFF, f); /* A */
2744 textureRow += 4;
2745 }
2746 /* take two rows of the pointer to the texture memory */
2747 if(swapChain)
2748 (textureRow-= width << 3);
2749
2750 }
2751 TRACE("Closing file\n");
2752 fclose(f);
2753
2754 if(swapChain) {
2755 IWineD3DSwapChain_Release(swapChain);
2756 }
2757 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2758 return WINED3D_OK;
2759}
2760
2761static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2762 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2763 HRESULT hr;
2764
2765 TRACE("(%p) : Calling base function first\n", This);
2766 hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
2767 if(SUCCEEDED(hr)) {
2768 This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
2769 TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
2770 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
2771 }
2772 return hr;
2773}
2774
2775static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2776 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2777
2778 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2779 WARN("Surface is locked or the HDC is in use\n");
2780 return WINED3DERR_INVALIDCALL;
2781 }
2782
2783 if(Mem && Mem != This->resource.allocatedMemory) {
2784 void *release = NULL;
2785
2786 /* Do I have to copy the old surface content? */
2787 if(This->Flags & SFLAG_DIBSECTION) {
2788 /* Release the DC. No need to hold the critical section for the update
2789 * Thread because this thread runs only on front buffers, but this method
2790 * fails for render targets in the check above.
2791 */
2792 SelectObject(This->hDC, This->dib.holdbitmap);
2793 DeleteDC(This->hDC);
2794 /* Release the DIB section */
2795 DeleteObject(This->dib.DIBsection);
2796 This->dib.bitmap_data = NULL;
2797 This->resource.allocatedMemory = NULL;
2798 This->hDC = NULL;
2799 This->Flags &= ~SFLAG_DIBSECTION;
2800 } else if(!(This->Flags & SFLAG_USERPTR)) {
2801 release = This->resource.heapMemory;
2802 This->resource.heapMemory = NULL;
2803 }
2804 This->resource.allocatedMemory = Mem;
2805 This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2806
2807 /* Now the surface memory is most up do date. Invalidate drawable and texture */
2808 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2809
2810 /* For client textures opengl has to be notified */
2811 if(This->Flags & SFLAG_CLIENT) {
2812 surface_release_client_storage(iface);
2813 }
2814
2815 /* Now free the old memory if any */
2816 HeapFree(GetProcessHeap(), 0, release);
2817 } else if(This->Flags & SFLAG_USERPTR) {
2818 /* LockRect and GetDC will re-create the dib section and allocated memory */
2819 This->resource.allocatedMemory = NULL;
2820 /* HeapMemory should be NULL already */
2821 if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
2822 This->Flags &= ~SFLAG_USERPTR;
2823
2824 if(This->Flags & SFLAG_CLIENT) {
2825 surface_release_client_storage(iface);
2826 }
2827 }
2828 return WINED3D_OK;
2829}
2830
2831void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
2832
2833 /* Flip the surface contents */
2834 /* Flip the DC */
2835 {
2836 HDC tmp;
2837 tmp = front->hDC;
2838 front->hDC = back->hDC;
2839 back->hDC = tmp;
2840 }
2841
2842 /* Flip the DIBsection */
2843 {
2844 HBITMAP tmp;
2845 BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
2846 tmp = front->dib.DIBsection;
2847 front->dib.DIBsection = back->dib.DIBsection;
2848 back->dib.DIBsection = tmp;
2849
2850 if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
2851 else front->Flags &= ~SFLAG_DIBSECTION;
2852 if(hasDib) back->Flags |= SFLAG_DIBSECTION;
2853 else back->Flags &= ~SFLAG_DIBSECTION;
2854 }
2855
2856 /* Flip the surface data */
2857 {
2858 void* tmp;
2859
2860 tmp = front->dib.bitmap_data;
2861 front->dib.bitmap_data = back->dib.bitmap_data;
2862 back->dib.bitmap_data = tmp;
2863
2864 tmp = front->resource.allocatedMemory;
2865 front->resource.allocatedMemory = back->resource.allocatedMemory;
2866 back->resource.allocatedMemory = tmp;
2867
2868 tmp = front->resource.heapMemory;
2869 front->resource.heapMemory = back->resource.heapMemory;
2870 back->resource.heapMemory = tmp;
2871 }
2872
2873 /* Flip the PBO */
2874 {
2875 GLuint tmp_pbo = front->pbo;
2876 front->pbo = back->pbo;
2877 back->pbo = tmp_pbo;
2878 }
2879
2880 /* client_memory should not be different, but just in case */
2881 {
2882 BOOL tmp;
2883 tmp = front->dib.client_memory;
2884 front->dib.client_memory = back->dib.client_memory;
2885 back->dib.client_memory = tmp;
2886 }
2887
2888 /* Flip the opengl texture */
2889 {
2890 GLuint tmp;
2891
2892 tmp = back->texture_name;
2893 back->texture_name = front->texture_name;
2894 front->texture_name = tmp;
2895
2896 tmp = back->texture_name_srgb;
2897 back->texture_name_srgb = front->texture_name_srgb;
2898 front->texture_name_srgb = tmp;
2899 }
2900
2901 {
2902 DWORD tmp_flags = back->Flags;
2903 back->Flags = front->Flags;
2904 front->Flags = tmp_flags;
2905 }
2906}
2907
2908static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2909 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2910 IWineD3DSwapChainImpl *swapchain = NULL;
2911 HRESULT hr;
2912 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2913
2914 /* Flipping is only supported on RenderTargets and overlays*/
2915 if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
2916 WARN("Tried to flip a non-render target, non-overlay surface\n");
2917 return WINEDDERR_NOTFLIPPABLE;
2918 }
2919
2920 if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
2921 flip_surface(This, (IWineD3DSurfaceImpl *) override);
2922
2923 /* Update the overlay if it is visible */
2924 if(This->overlay_dest) {
2925 return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
2926 } else {
2927 return WINED3D_OK;
2928 }
2929 }
2930
2931 if(override) {
2932 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2933 * FIXME("(%p) Target override is not supported by now\n", This);
2934 * Additionally, it isn't really possible to support triple-buffering
2935 * properly on opengl at all
2936 */
2937 }
2938
2939 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2940 if(!swapchain) {
2941 ERR("Flipped surface is not on a swapchain\n");
2942 return WINEDDERR_NOTFLIPPABLE;
2943 }
2944
2945 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2946 * and only d3d8 and d3d9 apps specify the presentation interval
2947 */
2948 if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2949 /* Most common case first to avoid wasting time on all the other cases */
2950 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2951 } else if(Flags & WINEDDFLIP_NOVSYNC) {
2952 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2953 } else if(Flags & WINEDDFLIP_INTERVAL2) {
2954 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2955 } else if(Flags & WINEDDFLIP_INTERVAL3) {
2956 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2957 } else {
2958 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2959 }
2960
2961 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2962 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *)swapchain,
2963 NULL, NULL, swapchain->win_handle, NULL, 0);
2964 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2965 return hr;
2966}
2967
2968/* Does a direct frame buffer -> texture copy. Stretching is done
2969 * with single pixel copy calls
2970 */
2971static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
2972 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
2973{
2974 IWineD3DDeviceImpl *myDevice = This->resource.device;
2975 float xrel, yrel;
2976 UINT row;
2977 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2978 struct wined3d_context *context;
2979 BOOL upsidedown = FALSE;
2980 RECT dst_rect = *dst_rect_in;
2981
2982 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2983 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2984 */
2985 if(dst_rect.top > dst_rect.bottom) {
2986 UINT tmp = dst_rect.bottom;
2987 dst_rect.bottom = dst_rect.top;
2988 dst_rect.top = tmp;
2989 upsidedown = TRUE;
2990 }
2991
2992 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
2993 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
2994 ENTER_GL();
2995
2996 /* Bind the target texture */
2997 glBindTexture(This->texture_target, This->texture_name);
2998 checkGLcall("glBindTexture");
2999 if(surface_is_offscreen(SrcSurface)) {
3000 TRACE("Reading from an offscreen target\n");
3001 upsidedown = !upsidedown;
3002 glReadBuffer(myDevice->offscreenBuffer);
3003 }
3004 else
3005 {
3006 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3007 }
3008 checkGLcall("glReadBuffer");
3009
3010 xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
3011 yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
3012
3013 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3014 {
3015 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3016
3017 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
3018 ERR("Texture filtering not supported in direct blit\n");
3019 }
3020 }
3021 else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
3022 && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3023 {
3024 ERR("Texture filtering not supported in direct blit\n");
3025 }
3026
3027 if (upsidedown
3028 && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3029 && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3030 {
3031 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3032
3033 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3034 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
3035 src_rect->left, Src->currentDesc.Height - src_rect->bottom,
3036 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3037 } else {
3038 UINT yoffset = Src->currentDesc.Height - src_rect->top + dst_rect.top - 1;
3039 /* I have to process this row by row to swap the image,
3040 * otherwise it would be upside down, so stretching in y direction
3041 * doesn't cost extra time
3042 *
3043 * However, stretching in x direction can be avoided if not necessary
3044 */
3045 for(row = dst_rect.top; row < dst_rect.bottom; row++) {
3046 if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3047 {
3048 /* Well, that stuff works, but it's very slow.
3049 * find a better way instead
3050 */
3051 UINT col;
3052
3053 for(col = dst_rect.left; col < dst_rect.right; col++) {
3054 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3055 dst_rect.left + col /* x offset */, row /* y offset */,
3056 src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3057 }
3058 } else {
3059 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3060 dst_rect.left /* x offset */, row /* y offset */,
3061 src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
3062 }
3063 }
3064 }
3065 checkGLcall("glCopyTexSubImage2D");
3066
3067 LEAVE_GL();
3068 context_release(context);
3069
3070 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3071 * path is never entered
3072 */
3073 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3074}
3075
3076/* Uses the hardware to stretch and flip the image */
3077static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3078 const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
3079{
3080 IWineD3DDeviceImpl *myDevice = This->resource.device;
3081 GLuint src, backup = 0;
3082 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3083 IWineD3DSwapChainImpl *src_swapchain = NULL;
3084 float left, right, top, bottom; /* Texture coordinates */
3085 UINT fbwidth = Src->currentDesc.Width;
3086 UINT fbheight = Src->currentDesc.Height;
3087 struct wined3d_context *context;
3088 GLenum drawBuffer = GL_BACK;
3089 GLenum texture_target;
3090 BOOL noBackBufferBackup;
3091 BOOL src_offscreen;
3092 BOOL upsidedown = FALSE;
3093 RECT dst_rect = *dst_rect_in;
3094
3095 TRACE("Using hwstretch blit\n");
3096 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3097 context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3098 surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3099
3100 src_offscreen = surface_is_offscreen(SrcSurface);
3101 noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3102 if (!noBackBufferBackup && !Src->texture_name)
3103 {
3104 /* Get it a description */
3105 surface_internal_preload(SrcSurface, SRGB_RGB);
3106 }
3107 ENTER_GL();
3108
3109 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3110 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3111 */
3112 if (context->aux_buffers >= 2)
3113 {
3114 /* Got more than one aux buffer? Use the 2nd aux buffer */
3115 drawBuffer = GL_AUX1;
3116 }
3117 else if ((!src_offscreen || myDevice->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3118 {
3119 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3120 drawBuffer = GL_AUX0;
3121 }
3122
3123 if(noBackBufferBackup) {
3124 glGenTextures(1, &backup);
3125 checkGLcall("glGenTextures");
3126 glBindTexture(GL_TEXTURE_2D, backup);
3127 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3128 texture_target = GL_TEXTURE_2D;
3129 } else {
3130 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3131 * we are reading from the back buffer, the backup can be used as source texture
3132 */
3133 texture_target = Src->texture_target;
3134 glBindTexture(texture_target, Src->texture_name);
3135 checkGLcall("glBindTexture(texture_target, Src->texture_name)");
3136 glEnable(texture_target);
3137 checkGLcall("glEnable(texture_target)");
3138
3139 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3140 Src->Flags &= ~SFLAG_INTEXTURE;
3141 }
3142
3143 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3144 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3145 */
3146 if(dst_rect.top > dst_rect.bottom) {
3147 UINT tmp = dst_rect.bottom;
3148 dst_rect.bottom = dst_rect.top;
3149 dst_rect.top = tmp;
3150 upsidedown = TRUE;
3151 }
3152
3153 if (src_offscreen)
3154 {
3155 TRACE("Reading from an offscreen target\n");
3156 upsidedown = !upsidedown;
3157 glReadBuffer(myDevice->offscreenBuffer);
3158 }
3159 else
3160 {
3161 glReadBuffer(surface_get_gl_buffer(SrcSurface));
3162 }
3163
3164 /* TODO: Only back up the part that will be overwritten */
3165 glCopyTexSubImage2D(texture_target, 0,
3166 0, 0 /* read offsets */,
3167 0, 0,
3168 fbwidth,
3169 fbheight);
3170
3171 checkGLcall("glCopyTexSubImage2D");
3172
3173 /* No issue with overriding these - the sampler is dirty due to blit usage */
3174 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3175 wined3d_gl_mag_filter(magLookup, Filter));
3176 checkGLcall("glTexParameteri");
3177 glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3178 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3179 checkGLcall("glTexParameteri");
3180
3181 IWineD3DSurface_GetContainer((IWineD3DSurface *)SrcSurface, &IID_IWineD3DSwapChain, (void **)&src_swapchain);
3182 if (src_swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *)src_swapchain);
3183 if (!src_swapchain || (IWineD3DSurface *) Src == src_swapchain->backBuffer[0]) {
3184 src = backup ? backup : Src->texture_name;
3185 } else {
3186 glReadBuffer(GL_FRONT);
3187 checkGLcall("glReadBuffer(GL_FRONT)");
3188
3189 glGenTextures(1, &src);
3190 checkGLcall("glGenTextures(1, &src)");
3191 glBindTexture(GL_TEXTURE_2D, src);
3192 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3193
3194 /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
3195 * out for power of 2 sizes
3196 */
3197 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
3198 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3199 checkGLcall("glTexImage2D");
3200 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3201 0, 0 /* read offsets */,
3202 0, 0,
3203 fbwidth,
3204 fbheight);
3205
3206 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3207 checkGLcall("glTexParameteri");
3208 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3209 checkGLcall("glTexParameteri");
3210
3211 glReadBuffer(GL_BACK);
3212 checkGLcall("glReadBuffer(GL_BACK)");
3213
3214 if(texture_target != GL_TEXTURE_2D) {
3215 glDisable(texture_target);
3216 glEnable(GL_TEXTURE_2D);
3217 texture_target = GL_TEXTURE_2D;
3218 }
3219 }
3220 checkGLcall("glEnd and previous");
3221
3222 left = src_rect->left;
3223 right = src_rect->right;
3224
3225 if(upsidedown) {
3226 top = Src->currentDesc.Height - src_rect->top;
3227 bottom = Src->currentDesc.Height - src_rect->bottom;
3228 } else {
3229 top = Src->currentDesc.Height - src_rect->bottom;
3230 bottom = Src->currentDesc.Height - src_rect->top;
3231 }
3232
3233 if(Src->Flags & SFLAG_NORMCOORD) {
3234 left /= Src->pow2Width;
3235 right /= Src->pow2Width;
3236 top /= Src->pow2Height;
3237 bottom /= Src->pow2Height;
3238 }
3239
3240 /* draw the source texture stretched and upside down. The correct surface is bound already */
3241 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3242 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3243
3244 context_set_draw_buffer(context, drawBuffer);
3245 glReadBuffer(drawBuffer);
3246
3247 glBegin(GL_QUADS);
3248 /* bottom left */
3249 glTexCoord2f(left, bottom);
3250 glVertex2i(0, fbheight);
3251
3252 /* top left */
3253 glTexCoord2f(left, top);
3254 glVertex2i(0, fbheight - dst_rect.bottom - dst_rect.top);
3255
3256 /* top right */
3257 glTexCoord2f(right, top);
3258 glVertex2i(dst_rect.right - dst_rect.left, fbheight - dst_rect.bottom - dst_rect.top);
3259
3260 /* bottom right */
3261 glTexCoord2f(right, bottom);
3262 glVertex2i(dst_rect.right - dst_rect.left, fbheight);
3263 glEnd();
3264 checkGLcall("glEnd and previous");
3265
3266 if (texture_target != This->texture_target)
3267 {
3268 glDisable(texture_target);
3269 glEnable(This->texture_target);
3270 texture_target = This->texture_target;
3271 }
3272
3273 /* Now read the stretched and upside down image into the destination texture */
3274 glBindTexture(texture_target, This->texture_name);
3275 checkGLcall("glBindTexture");
3276 glCopyTexSubImage2D(texture_target,
3277 0,
3278 dst_rect.left, dst_rect.top, /* xoffset, yoffset */
3279 0, 0, /* We blitted the image to the origin */
3280 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
3281 checkGLcall("glCopyTexSubImage2D");
3282
3283 if(drawBuffer == GL_BACK) {
3284 /* Write the back buffer backup back */
3285 if(backup) {
3286 if(texture_target != GL_TEXTURE_2D) {
3287 glDisable(texture_target);
3288 glEnable(GL_TEXTURE_2D);
3289 texture_target = GL_TEXTURE_2D;
3290 }
3291 glBindTexture(GL_TEXTURE_2D, backup);
3292 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3293 } else {
3294 if (texture_target != Src->texture_target)
3295 {
3296 glDisable(texture_target);
3297 glEnable(Src->texture_target);
3298 texture_target = Src->texture_target;
3299 }
3300 glBindTexture(Src->texture_target, Src->texture_name);
3301 checkGLcall("glBindTexture(Src->texture_target, Src->texture_name)");
3302 }
3303
3304 glBegin(GL_QUADS);
3305 /* top left */
3306 glTexCoord2f(0.0f, (float)fbheight / (float)Src->pow2Height);
3307 glVertex2i(0, 0);
3308
3309 /* bottom left */
3310 glTexCoord2f(0.0f, 0.0f);
3311 glVertex2i(0, fbheight);
3312
3313 /* bottom right */
3314 glTexCoord2f((float)fbwidth / (float)Src->pow2Width, 0.0f);
3315 glVertex2i(fbwidth, Src->currentDesc.Height);
3316
3317 /* top right */
3318 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
3319 glVertex2i(fbwidth, 0);
3320 glEnd();
3321 }
3322 glDisable(texture_target);
3323 checkGLcall("glDisable(texture_target)");
3324
3325 /* Cleanup */
3326 if (src != Src->texture_name && src != backup)
3327 {
3328 glDeleteTextures(1, &src);
3329 checkGLcall("glDeleteTextures(1, &src)");
3330 }
3331 if(backup) {
3332 glDeleteTextures(1, &backup);
3333 checkGLcall("glDeleteTextures(1, &backup)");
3334 }
3335
3336 LEAVE_GL();
3337
3338 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
3339
3340 context_release(context);
3341
3342 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3343 * path is never entered
3344 */
3345 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3346}
3347
3348/* Until the blit_shader is ready, define some prototypes here. */
3349static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
3350 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
3351 const struct wined3d_format_desc *src_format_desc,
3352 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
3353 const struct wined3d_format_desc *dst_format_desc);
3354
3355/* Not called from the VTable */
3356static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3357 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3358 WINED3DTEXTUREFILTERTYPE Filter)
3359{
3360 IWineD3DDeviceImpl *myDevice = This->resource.device;
3361 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3362 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3363 RECT dst_rect, src_rect;
3364
3365 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3366
3367 /* Get the swapchain. One of the surfaces has to be a primary surface */
3368 if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3369 WARN("Destination is in sysmem, rejecting gl blt\n");
3370 return WINED3DERR_INVALIDCALL;
3371 }
3372 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3373 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
3374 if(Src) {
3375 if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3376 WARN("Src is in sysmem, rejecting gl blt\n");
3377 return WINED3DERR_INVALIDCALL;
3378 }
3379 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3380 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
3381 }
3382
3383 /* Early sort out of cases where no render target is used */
3384 if(!dstSwapchain && !srcSwapchain &&
3385 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3386 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
3387 return WINED3DERR_INVALIDCALL;
3388 }
3389
3390 /* No destination color keying supported */
3391 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3392 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3393 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3394 return WINED3DERR_INVALIDCALL;
3395 }
3396
3397 surface_get_rect(This, DestRect, &dst_rect);
3398 if(Src) surface_get_rect(Src, SrcRect, &src_rect);
3399
3400 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3401 if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
3402 ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
3403 /* Half-life does a Blt from the back buffer to the front buffer,
3404 * Full surface size, no flags... Use present instead
3405 *
3406 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3407 */
3408
3409 /* Check rects - IWineD3DDevice_Present doesn't handle them */
3410 while(1)
3411 {
3412 TRACE("Looking if a Present can be done...\n");
3413 /* Source Rectangle must be full surface */
3414 if(src_rect.left != 0 || src_rect.top != 0 ||
3415 src_rect.right != Src->currentDesc.Width || src_rect.bottom != Src->currentDesc.Height) {
3416 TRACE("No, Source rectangle doesn't match\n");
3417 break;
3418 }
3419
3420 /* No stretching may occur */
3421 if(src_rect.right != dst_rect.right - dst_rect.left ||
3422 src_rect.bottom != dst_rect.bottom - dst_rect.top) {
3423 TRACE("No, stretching is done\n");
3424 break;
3425 }
3426
3427 /* Destination must be full surface or match the clipping rectangle */
3428 if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
3429 {
3430 RECT cliprect;
3431 POINT pos[2];
3432 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
3433 pos[0].x = dst_rect.left;
3434 pos[0].y = dst_rect.top;
3435 pos[1].x = dst_rect.right;
3436 pos[1].y = dst_rect.bottom;
3437 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
3438 pos, 2);
3439
3440 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
3441 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3442 {
3443 TRACE("No, dest rectangle doesn't match(clipper)\n");
3444 TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
3445 TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
3446 break;
3447 }
3448 }
3449 else
3450 {
3451 if(dst_rect.left != 0 || dst_rect.top != 0 ||
3452 dst_rect.right != This->currentDesc.Width || dst_rect.bottom != This->currentDesc.Height) {
3453 TRACE("No, dest rectangle doesn't match(surface size)\n");
3454 break;
3455 }
3456 }
3457
3458 TRACE("Yes\n");
3459
3460 /* These flags are unimportant for the flag check, remove them */
3461 if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3462 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3463
3464 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3465 * take very long, while a flip is fast.
3466 * This applies to Half-Life, which does such Blts every time it finished
3467 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3468 * menu. This is also used by all apps when they do windowed rendering
3469 *
3470 * The problem is that flipping is not really the same as copying. After a
3471 * Blt the front buffer is a copy of the back buffer, and the back buffer is
3472 * untouched. Therefore it's necessary to override the swap effect
3473 * and to set it back after the flip.
3474 *
3475 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3476 * testcases.
3477 */
3478
3479 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3480 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3481
3482 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3483 IWineD3DSwapChain_Present((IWineD3DSwapChain *)dstSwapchain,
3484 NULL, NULL, dstSwapchain->win_handle, NULL, 0);
3485
3486 dstSwapchain->presentParms.SwapEffect = orig_swap;
3487
3488 return WINED3D_OK;
3489 }
3490 break;
3491 }
3492
3493 TRACE("Unsupported blit between buffers on the same swapchain\n");
3494 return WINED3DERR_INVALIDCALL;
3495 } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3496 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3497 return WINED3DERR_INVALIDCALL;
3498 } else if(dstSwapchain && srcSwapchain) {
3499 FIXME("Implement hardware blit between two different swapchains\n");
3500 return WINED3DERR_INVALIDCALL;
3501 } else if(dstSwapchain) {
3502 if(SrcSurface == myDevice->render_targets[0]) {
3503 TRACE("Blit from active render target to a swapchain\n");
3504 /* Handled with regular texture -> swapchain blit */
3505 }
3506 } else if(srcSwapchain && This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3507 FIXME("Implement blit from a swapchain to the active render target\n");
3508 return WINED3DERR_INVALIDCALL;
3509 }
3510
3511 if((srcSwapchain || SrcSurface == myDevice->render_targets[0]) && !dstSwapchain) {
3512 /* Blit from render target to texture */
3513 BOOL stretchx;
3514
3515 /* P8 read back is not implemented */
3516 if (Src->resource.format_desc->format == WINED3DFMT_P8_UINT ||
3517 This->resource.format_desc->format == WINED3DFMT_P8_UINT)
3518 {
3519 TRACE("P8 read back not supported by frame buffer to texture blit\n");
3520 return WINED3DERR_INVALIDCALL;
3521 }
3522
3523 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3524 TRACE("Color keying not supported by frame buffer to texture blit\n");
3525 return WINED3DERR_INVALIDCALL;
3526 /* Destination color key is checked above */
3527 }
3528
3529 if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
3530 stretchx = TRUE;
3531 } else {
3532 stretchx = FALSE;
3533 }
3534
3535 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3536 * flip the image nor scale it.
3537 *
3538 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3539 * -> If the app wants a image width an unscaled width, copy it line per line
3540 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3541 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3542 * back buffer. This is slower than reading line per line, thus not used for flipping
3543 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3544 * pixel by pixel
3545 *
3546 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3547 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3548 * backends.
3549 */
3550 if (fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3551 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3552 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3553 {
3554 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3555 (IWineD3DSurface *)This, &dst_rect, Filter);
3556 } else if((!stretchx) || dst_rect.right - dst_rect.left > Src->currentDesc.Width ||
3557 dst_rect.bottom - dst_rect.top > Src->currentDesc.Height) {
3558 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3559 fb_copy_to_texture_direct(This, SrcSurface, &src_rect, &dst_rect, Filter);
3560 } else {
3561 TRACE("Using hardware stretching to flip / stretch the texture\n");
3562 fb_copy_to_texture_hwstretch(This, SrcSurface, &src_rect, &dst_rect, Filter);
3563 }
3564
3565 if(!(This->Flags & SFLAG_DONOTFREE)) {
3566 HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3567 This->resource.allocatedMemory = NULL;
3568 This->resource.heapMemory = NULL;
3569 } else {
3570 This->Flags &= ~SFLAG_INSYSMEM;
3571 }
3572
3573 return WINED3D_OK;
3574 } else if(Src) {
3575 /* Blit from offscreen surface to render target */
3576 DWORD oldCKeyFlags = Src->CKeyFlags;
3577 WINEDDCOLORKEY oldBltCKey = Src->SrcBltCKey;
3578 struct wined3d_context *context;
3579
3580 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3581
3582 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3583 && fbo_blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3584 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3585 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3586 {
3587 TRACE("Using stretch_rect_fbo\n");
3588 /* The source is always a texture, but never the currently active render target, and the texture
3589 * contents are never upside down
3590 */
3591 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &src_rect,
3592 (IWineD3DSurface *)This, &dst_rect, Filter);
3593 return WINED3D_OK;
3594 }
3595
3596 if (!(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3597 && arbfp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3598 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3599 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3600 {
3601 return arbfp_blit_surface(myDevice, Src, &src_rect, This, &dst_rect, BLIT_OP_BLIT, Filter);
3602 }
3603
3604 /* Color keying: Check if we have to do a color keyed blt,
3605 * and if not check if a color key is activated.
3606 *
3607 * Just modify the color keying parameters in the surface and restore them afterwards
3608 * The surface keeps track of the color key last used to load the opengl surface.
3609 * PreLoad will catch the change to the flags and color key and reload if necessary.
3610 */
3611 if(Flags & WINEDDBLT_KEYSRC) {
3612 /* Use color key from surface */
3613 } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3614 /* Use color key from DDBltFx */
3615 Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
3616 Src->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3617 } else {
3618 /* Do not use color key */
3619 Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3620 }
3621
3622 /* Now load the surface */
3623 surface_internal_preload((IWineD3DSurface *) Src, SRGB_RGB);
3624
3625 /* Activate the destination context, set it up for blitting */
3626 context = context_acquire(myDevice, (IWineD3DSurface *)This, CTXUSAGE_BLIT);
3627
3628 /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
3629 * while OpenGL coordinates are window relative.
3630 * Also beware of the origin difference(top left vs bottom left).
3631 * Also beware that the front buffer's surface size is screen width x screen height,
3632 * whereas the real gl drawable size is the size of the window.
3633 */
3634 if (dstSwapchain && (IWineD3DSurface *)This == dstSwapchain->frontBuffer) {
3635 RECT windowsize;
3636 POINT offset = {0,0};
3637 UINT h;
3638 ClientToScreen(context->win_handle, &offset);
3639 GetClientRect(context->win_handle, &windowsize);
3640 h = windowsize.bottom - windowsize.top;
3641 dst_rect.left -= offset.x; dst_rect.right -=offset.x;
3642 dst_rect.top -= offset.y; dst_rect.bottom -=offset.y;
3643 dst_rect.top += This->currentDesc.Height - h; dst_rect.bottom += This->currentDesc.Height - h;
3644 }
3645
3646 if (!myDevice->blitter->blit_supported(&myDevice->adapter->gl_info, BLIT_OP_BLIT,
3647 &src_rect, Src->resource.usage, Src->resource.pool, Src->resource.format_desc,
3648 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3649 {
3650 FIXME("Unsupported blit operation falling back to software\n");
3651 return WINED3DERR_INVALIDCALL;
3652 }
3653
3654 myDevice->blitter->set_shader((IWineD3DDevice *) myDevice, Src);
3655
3656 ENTER_GL();
3657
3658 /* This is for color keying */
3659 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3660 glEnable(GL_ALPHA_TEST);
3661 checkGLcall("glEnable(GL_ALPHA_TEST)");
3662
3663 /* When the primary render target uses P8, the alpha component contains the palette index.
3664 * Which means that the colorkey is one of the palette entries. In other cases pixels that
3665 * should be masked away have alpha set to 0. */
3666 if(primary_render_target_is_p8(myDevice))
3667 glAlphaFunc(GL_NOTEQUAL, (float)Src->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
3668 else
3669 glAlphaFunc(GL_NOTEQUAL, 0.0f);
3670 checkGLcall("glAlphaFunc");
3671 } else {
3672 glDisable(GL_ALPHA_TEST);
3673 checkGLcall("glDisable(GL_ALPHA_TEST)");
3674 }
3675
3676 /* Draw a textured quad
3677 */
3678 draw_textured_quad(Src, &src_rect, &dst_rect, Filter);
3679
3680 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3681 glDisable(GL_ALPHA_TEST);
3682 checkGLcall("glDisable(GL_ALPHA_TEST)");
3683 }
3684
3685 /* Restore the color key parameters */
3686 Src->CKeyFlags = oldCKeyFlags;
3687 Src->SrcBltCKey = oldBltCKey;
3688
3689 LEAVE_GL();
3690
3691 /* Leave the opengl state valid for blitting */
3692 myDevice->blitter->unset_shader((IWineD3DDevice *) myDevice);
3693
3694 if (wined3d_settings.strict_draw_ordering || (dstSwapchain
3695 && ((IWineD3DSurface *)This == dstSwapchain->frontBuffer
3696 || dstSwapchain->num_contexts > 1)))
3697 wglFlush(); /* Flush to ensure ordering across contexts. */
3698
3699 context_release(context);
3700
3701 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3702 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3703 * is outdated now
3704 */
3705 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE);
3706
3707 return WINED3D_OK;
3708 } else {
3709 /* Source-Less Blit to render target */
3710 if (Flags & WINEDDBLT_COLORFILL) {
3711 DWORD color;
3712
3713 TRACE("Colorfill\n");
3714
3715 /* The color as given in the Blt function is in the format of the frame-buffer...
3716 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3717 */
3718 if (!surface_convert_color_to_argb(This, DDBltFx->u5.dwFillColor, &color))
3719 {
3720 /* The color conversion function already prints an error, so need to do it here */
3721 return WINED3DERR_INVALIDCALL;
3722 }
3723
3724 if (ffp_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
3725 NULL, 0, 0, NULL,
3726 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3727 {
3728 return ffp_blit.color_fill(myDevice, This, &dst_rect, color);
3729 }
3730 else if (cpu_blit.blit_supported(&myDevice->adapter->gl_info, BLIT_OP_COLOR_FILL,
3731 NULL, 0, 0, NULL,
3732 &dst_rect, This->resource.usage, This->resource.pool, This->resource.format_desc))
3733 {
3734 return cpu_blit.color_fill(myDevice, This, &dst_rect, color);
3735 }
3736 return WINED3DERR_INVALIDCALL;
3737 }
3738 }
3739
3740 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3741 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3742 return WINED3DERR_INVALIDCALL;
3743}
3744
3745static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3746 IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
3747{
3748 IWineD3DDeviceImpl *myDevice = This->resource.device;
3749 float depth;
3750
3751 if (Flags & WINEDDBLT_DEPTHFILL) {
3752 switch(This->resource.format_desc->format)
3753 {
3754 case WINED3DFMT_D16_UNORM:
3755 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
3756 break;
3757 case WINED3DFMT_S1_UINT_D15_UNORM:
3758 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
3759 break;
3760 case WINED3DFMT_D24_UNORM_S8_UINT:
3761 case WINED3DFMT_X8D24_UNORM:
3762 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
3763 break;
3764 case WINED3DFMT_D32_UNORM:
3765 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
3766 break;
3767 default:
3768 depth = 0.0f;
3769 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
3770 }
3771
3772 return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3773 DestRect == NULL ? 0 : 1,
3774 (const WINED3DRECT *)DestRect,
3775 WINED3DCLEAR_ZBUFFER,
3776 0x00000000,
3777 depth,
3778 0x00000000);
3779 }
3780
3781 FIXME("(%p): Unsupp depthstencil blit\n", This);
3782 return WINED3DERR_INVALIDCALL;
3783}
3784
3785static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
3786 const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3787 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3788 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3789 IWineD3DDeviceImpl *myDevice = This->resource.device;
3790
3791 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3792 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3793
3794 if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
3795 {
3796 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3797 return WINEDDERR_SURFACEBUSY;
3798 }
3799
3800 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3801 * except depth blits, which seem to work
3802 */
3803 if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3804 if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3805 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3806 return WINED3DERR_INVALIDCALL;
3807 } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3808 TRACE("Z Blit override handled the blit\n");
3809 return WINED3D_OK;
3810 }
3811 }
3812
3813 /* Special cases for RenderTargets */
3814 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3815 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3816 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3817 }
3818
3819 /* For the rest call the X11 surface implementation.
3820 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3821 * other Blts are rather rare
3822 */
3823 return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3824}
3825
3826static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
3827 IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
3828{
3829 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3830 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3831 IWineD3DDeviceImpl *myDevice = This->resource.device;
3832
3833 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3834
3835 if ( (This->Flags & SFLAG_LOCKED) || (srcImpl->Flags & SFLAG_LOCKED))
3836 {
3837 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3838 return WINEDDERR_SURFACEBUSY;
3839 }
3840
3841 if(myDevice->inScene &&
3842 (iface == myDevice->stencilBufferTarget ||
3843 (Source == myDevice->stencilBufferTarget))) {
3844 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3845 return WINED3DERR_INVALIDCALL;
3846 }
3847
3848 /* Special cases for RenderTargets */
3849 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3850 (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
3851
3852 RECT SrcRect, DstRect;
3853 DWORD Flags=0;
3854
3855 surface_get_rect(srcImpl, rsrc, &SrcRect);
3856
3857 DstRect.left = dstx;
3858 DstRect.top=dsty;
3859 DstRect.right = dstx + SrcRect.right - SrcRect.left;
3860 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3861
3862 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3863 if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3864 Flags |= WINEDDBLT_KEYSRC;
3865 if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3866 Flags |= WINEDDBLT_KEYDEST;
3867 if(trans & WINEDDBLTFAST_WAIT)
3868 Flags |= WINEDDBLT_WAIT;
3869 if(trans & WINEDDBLTFAST_DONOTWAIT)
3870 Flags |= WINEDDBLT_DONOTWAIT;
3871
3872 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3873 }
3874
3875
3876 return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3877}
3878
3879static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
3880{
3881 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3882 RGBQUAD col[256];
3883 IWineD3DPaletteImpl *pal = This->palette;
3884 unsigned int n;
3885 TRACE("(%p)\n", This);
3886
3887 if (!pal) return WINED3D_OK;
3888
3889 if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
3890 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
3891 {
3892 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3893 {
3894 /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
3895 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
3896
3897 /* We want to force a palette refresh, so mark the drawable as not being up to date */
3898 IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
3899 } else {
3900 if(!(This->Flags & SFLAG_INSYSMEM)) {
3901 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
3902 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
3903 }
3904 TRACE("Dirtifying surface\n");
3905 IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
3906 }
3907 }
3908
3909 if(This->Flags & SFLAG_DIBSECTION) {
3910 TRACE("(%p): Updating the hdc's palette\n", This);
3911 for (n=0; n<256; n++) {
3912 col[n].rgbRed = pal->palents[n].peRed;
3913 col[n].rgbGreen = pal->palents[n].peGreen;
3914 col[n].rgbBlue = pal->palents[n].peBlue;
3915 col[n].rgbReserved = 0;
3916 }
3917 SetDIBColorTable(This->hDC, 0, 256, col);
3918 }
3919
3920 /* Propagate the changes to the drawable when we have a palette. */
3921 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3922 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, NULL);
3923
3924 return WINED3D_OK;
3925}
3926
3927static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3928 /** Check against the maximum texture sizes supported by the video card **/
3929 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3930 const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
3931 unsigned int pow2Width, pow2Height;
3932
3933 This->texture_name = 0;
3934 This->texture_target = GL_TEXTURE_2D;
3935
3936 /* Non-power2 support */
3937 if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINE_NORMALIZED_TEXRECT])
3938 {
3939 pow2Width = This->currentDesc.Width;
3940 pow2Height = This->currentDesc.Height;
3941 }
3942 else
3943 {
3944 /* Find the nearest pow2 match */
3945 pow2Width = pow2Height = 1;
3946 while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3947 while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3948 }
3949 This->pow2Width = pow2Width;
3950 This->pow2Height = pow2Height;
3951
3952 if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3953 /** TODO: add support for non power two compressed textures **/
3954 if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
3955 {
3956 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3957 This, This->currentDesc.Width, This->currentDesc.Height);
3958 return WINED3DERR_NOTAVAILABLE;
3959 }
3960 }
3961
3962 if(pow2Width != This->currentDesc.Width ||
3963 pow2Height != This->currentDesc.Height) {
3964 This->Flags |= SFLAG_NONPOW2;
3965 }
3966
3967 TRACE("%p\n", This);
3968 if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
3969 && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
3970 {
3971 /* one of three options
3972 1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
3973 2: Set the texture to the maximum size (bad idea)
3974 3: WARN and return WINED3DERR_NOTAVAILABLE;
3975 4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
3976 */
3977 if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
3978 {
3979 WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
3980 return WINED3DERR_NOTAVAILABLE;
3981 }
3982
3983 /* We should never use this surface in combination with OpenGL! */
3984 TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
3985 }
3986 else
3987 {
3988 /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
3989 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
3990 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
3991 */
3992 if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
3993 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
3994 && gl_info->supported[EXT_PALETTED_TEXTURE]
3995 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
3996 {
3997 This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
3998 This->pow2Width = This->currentDesc.Width;
3999 This->pow2Height = This->currentDesc.Height;
4000 This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4001 }
4002 }
4003
4004 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4005 switch(wined3d_settings.offscreen_rendering_mode) {
4006 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
4007 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4008 }
4009 }
4010
4011 This->Flags |= SFLAG_INSYSMEM;
4012
4013 return WINED3D_OK;
4014}
4015
4016/* GL locking is done by the caller */
4017static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
4018 GLuint texture, GLsizei w, GLsizei h, GLenum target)
4019{
4020 IWineD3DDeviceImpl *device = This->resource.device;
4021 struct blt_info info;
4022 GLint old_binding = 0;
4023
4024 glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4025
4026 glDisable(GL_CULL_FACE);
4027 glDisable(GL_BLEND);
4028 glDisable(GL_ALPHA_TEST);
4029 glDisable(GL_SCISSOR_TEST);
4030 glDisable(GL_STENCIL_TEST);
4031 glEnable(GL_DEPTH_TEST);
4032 glDepthFunc(GL_ALWAYS);
4033 glDepthMask(GL_TRUE);
4034 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4035 glViewport(0, 0, w, h);
4036
4037 surface_get_blt_info(target, NULL, w, h, &info);
4038 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4039 glGetIntegerv(info.binding, &old_binding);
4040 glBindTexture(info.bind_target, texture);
4041
4042 device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device, info.tex_type);
4043
4044 glBegin(GL_TRIANGLE_STRIP);
4045 glTexCoord3fv(info.coords[0]);
4046 glVertex2f(-1.0f, -1.0f);
4047 glTexCoord3fv(info.coords[1]);
4048 glVertex2f(1.0f, -1.0f);
4049 glTexCoord3fv(info.coords[2]);
4050 glVertex2f(-1.0f, 1.0f);
4051 glTexCoord3fv(info.coords[3]);
4052 glVertex2f(1.0f, 1.0f);
4053 glEnd();
4054
4055 glBindTexture(info.bind_target, old_binding);
4056
4057 glPopAttrib();
4058
4059 device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4060}
4061
4062void surface_modify_ds_location(IWineD3DSurface *iface, DWORD location) {
4063 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4064
4065 TRACE("(%p) New location %#x\n", This, location);
4066
4067 if (location & ~SFLAG_DS_LOCATIONS) {
4068 FIXME("(%p) Invalid location (%#x) specified\n", This, location);
4069 }
4070
4071 This->Flags &= ~SFLAG_DS_LOCATIONS;
4072 This->Flags |= location;
4073}
4074
4075/* Context activation is done by the caller. */
4076void surface_load_ds_location(IWineD3DSurface *iface, struct wined3d_context *context, DWORD location)
4077{
4078 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4079 IWineD3DDeviceImpl *device = This->resource.device;
4080 const struct wined3d_gl_info *gl_info = context->gl_info;
4081
4082 TRACE("(%p) New location %#x\n", This, location);
4083
4084 /* TODO: Make this work for modes other than FBO */
4085 if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4086
4087 if (This->Flags & location) {
4088 TRACE("(%p) Location (%#x) is already up to date\n", This, location);
4089 return;
4090 }
4091
4092 if (This->current_renderbuffer) {
4093 FIXME("(%p) Not supported with fixed up depth stencil\n", This);
4094 return;
4095 }
4096
4097 if (location == SFLAG_DS_OFFSCREEN) {
4098 if (This->Flags & SFLAG_DS_ONSCREEN) {
4099 GLint old_binding = 0;
4100 GLenum bind_target;
4101
4102 TRACE("(%p) Copying onscreen depth buffer to depth texture\n", This);
4103
4104 ENTER_GL();
4105
4106 if (!device->depth_blt_texture) {
4107 glGenTextures(1, &device->depth_blt_texture);
4108 }
4109
4110 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4111 * directly on the FBO texture. That's because we need to flip. */
4112 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4113 if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4114 {
4115 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4116 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4117 } else {
4118 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4119 bind_target = GL_TEXTURE_2D;
4120 }
4121 glBindTexture(bind_target, device->depth_blt_texture);
4122 glCopyTexImage2D(bind_target, This->texture_level, This->resource.format_desc->glInternal,
4123 0, 0, This->currentDesc.Width, This->currentDesc.Height, 0);
4124 glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4125 glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4126 glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4127 glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4128 glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4129 glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4130 glBindTexture(bind_target, old_binding);
4131
4132 /* Setup the destination */
4133 if (!device->depth_blt_rb) {
4134 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4135 checkGLcall("glGenRenderbuffersEXT");
4136 }
4137 if (device->depth_blt_rb_w != This->currentDesc.Width
4138 || device->depth_blt_rb_h != This->currentDesc.Height) {
4139 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4140 checkGLcall("glBindRenderbufferEXT");
4141 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4142 This->currentDesc.Width, This->currentDesc.Height);
4143 checkGLcall("glRenderbufferStorageEXT");
4144 device->depth_blt_rb_w = This->currentDesc.Width;
4145 device->depth_blt_rb_h = This->currentDesc.Height;
4146 }
4147
4148 context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4149 gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4150 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4151 checkGLcall("glFramebufferRenderbufferEXT");
4152 context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, This, FALSE);
4153
4154 /* Do the actual blit */
4155 surface_depth_blt(This, gl_info, device->depth_blt_texture,
4156 This->currentDesc.Width, This->currentDesc.Height, bind_target);
4157 checkGLcall("depth_blt");
4158
4159 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4160 else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4161
4162 LEAVE_GL();
4163
4164 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4165 }
4166 else
4167 {
4168 FIXME("No up to date depth stencil location\n");
4169 }
4170 } else if (location == SFLAG_DS_ONSCREEN) {
4171 if (This->Flags & SFLAG_DS_OFFSCREEN) {
4172 TRACE("(%p) Copying depth texture to onscreen depth buffer\n", This);
4173
4174 ENTER_GL();
4175
4176 context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4177 surface_depth_blt(This, gl_info, This->texture_name,
4178 This->currentDesc.Width, This->currentDesc.Height, This->texture_target);
4179 checkGLcall("depth_blt");
4180
4181 if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4182
4183 LEAVE_GL();
4184
4185 if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
4186 }
4187 else
4188 {
4189 FIXME("No up to date depth stencil location\n");
4190 }
4191 } else {
4192 ERR("(%p) Invalid location (%#x) specified\n", This, location);
4193 }
4194
4195 This->Flags |= location;
4196}
4197
4198static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
4199 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4200 IWineD3DBaseTexture *texture;
4201 IWineD3DSurfaceImpl *overlay;
4202
4203 TRACE("(%p)->(%s, %s)\n", iface, debug_surflocation(flag),
4204 persistent ? "TRUE" : "FALSE");
4205
4206 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4207 if (surface_is_offscreen(iface))
4208 {
4209 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4210 if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4211 }
4212 else
4213 {
4214 TRACE("Surface %p is an onscreen surface\n", iface);
4215 }
4216 }
4217
4218 if(persistent) {
4219 if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) ||
4220 ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) {
4221 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4222 TRACE("Passing to container\n");
4223 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4224 IWineD3DBaseTexture_Release(texture);
4225 }
4226 }
4227 This->Flags &= ~SFLAG_LOCATIONS;
4228 This->Flags |= flag;
4229
4230 /* Redraw emulated overlays, if any */
4231 if(flag & SFLAG_INDRAWABLE && !list_empty(&This->overlays)) {
4232 LIST_FOR_EACH_ENTRY(overlay, &This->overlays, IWineD3DSurfaceImpl, overlay_entry) {
4233 IWineD3DSurface_DrawOverlay((IWineD3DSurface *) overlay);
4234 }
4235 }
4236 } else {
4237 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) {
4238 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4239 TRACE("Passing to container\n");
4240 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4241 IWineD3DBaseTexture_Release(texture);
4242 }
4243 }
4244 This->Flags &= ~flag;
4245 }
4246
4247 if(!(This->Flags & SFLAG_LOCATIONS)) {
4248 ERR("%p: Surface does not have any up to date location\n", This);
4249 }
4250}
4251
4252static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4253{
4254 IWineD3DDeviceImpl *device = This->resource.device;
4255 IWineD3DSwapChainImpl *swapchain;
4256 struct wined3d_context *context;
4257 RECT src_rect, dst_rect;
4258
4259 surface_get_rect(This, rect_in, &src_rect);
4260
4261 context = context_acquire(device, (IWineD3DSurface*)This, CTXUSAGE_BLIT);
4262 if (context->render_offscreen)
4263 {
4264 dst_rect.left = src_rect.left;
4265 dst_rect.right = src_rect.right;
4266 dst_rect.top = src_rect.bottom;
4267 dst_rect.bottom = src_rect.top;
4268 }
4269 else
4270 {
4271 dst_rect = src_rect;
4272 }
4273
4274 device->blitter->set_shader((IWineD3DDevice *) device, This);
4275
4276 ENTER_GL();
4277 draw_textured_quad(This, &src_rect, &dst_rect, WINED3DTEXF_POINT);
4278 LEAVE_GL();
4279
4280 device->blitter->set_shader((IWineD3DDevice *) device, This);
4281
4282 swapchain = (This->Flags & SFLAG_SWAPCHAIN) ? (IWineD3DSwapChainImpl *)This->container : NULL;
4283 if (wined3d_settings.strict_draw_ordering || (swapchain
4284 && ((IWineD3DSurface *)This == swapchain->frontBuffer
4285 || swapchain->num_contexts > 1)))
4286 wglFlush(); /* Flush to ensure ordering across contexts. */
4287
4288 context_release(context);
4289}
4290
4291/*****************************************************************************
4292 * IWineD3DSurface::LoadLocation
4293 *
4294 * Copies the current surface data from wherever it is to the requested
4295 * location. The location is one of the surface flags, SFLAG_INSYSMEM,
4296 * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
4297 * multiple locations, the gl texture is preferred over the drawable, which is
4298 * preferred over system memory. The PBO counts as system memory. If rect is
4299 * not NULL, only the specified rectangle is copied (only supported for
4300 * sysmem<->drawable copies at the moment). If rect is NULL, the destination
4301 * location is marked up to date after the copy.
4302 *
4303 * Parameters:
4304 * flag: Surface location flag to be updated
4305 * rect: rectangle to be copied
4306 *
4307 * Returns:
4308 * WINED3D_OK on success
4309 * WINED3DERR_DEVICELOST on an internal error
4310 *
4311 *****************************************************************************/
4312static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
4313 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4314 IWineD3DDeviceImpl *device = This->resource.device;
4315 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4316 struct wined3d_format_desc desc;
4317 CONVERT_TYPES convert;
4318 int width, pitch, outpitch;
4319 BYTE *mem;
4320 BOOL drawable_read_ok = TRUE;
4321 BOOL in_fbo = FALSE;
4322
4323 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4324 if (surface_is_offscreen(iface))
4325 {
4326 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4327 * Prefer SFLAG_INTEXTURE. */
4328 if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
4329 drawable_read_ok = FALSE;
4330 in_fbo = TRUE;
4331 }
4332 else
4333 {
4334 TRACE("Surface %p is an onscreen surface\n", iface);
4335 }
4336 }
4337
4338 TRACE("(%p)->(%s, %p)\n", iface, debug_surflocation(flag), rect);
4339 if(rect) {
4340 TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
4341 }
4342
4343 if(This->Flags & flag) {
4344 TRACE("Location already up to date\n");
4345 return WINED3D_OK;
4346 }
4347
4348 if(!(This->Flags & SFLAG_LOCATIONS)) {
4349 ERR("%p: Surface does not have any up to date location\n", This);
4350 This->Flags |= SFLAG_LOST;
4351 return WINED3DERR_DEVICELOST;
4352 }
4353
4354 if(flag == SFLAG_INSYSMEM) {
4355 surface_prepare_system_memory(This);
4356
4357 /* Download the surface to system memory */
4358 if (This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
4359 {
4360 struct wined3d_context *context = NULL;
4361
4362 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4363
4364 surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE));
4365 surface_download_data(This, gl_info);
4366
4367 if (context) context_release(context);
4368 }
4369 else
4370 {
4371 /* Note: It might be faster to download into a texture first. */
4372 read_from_framebuffer(This, rect,
4373 This->resource.allocatedMemory,
4374 IWineD3DSurface_GetPitch(iface));
4375 }
4376 } else if(flag == SFLAG_INDRAWABLE) {
4377 if(This->Flags & SFLAG_INTEXTURE) {
4378 surface_blt_to_drawable(This, rect);
4379 } else {
4380 int byte_count;
4381 if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) {
4382 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4383 * values, otherwise we get incorrect values in the target. For now go the slow way
4384 * via a system memory copy
4385 */
4386 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4387 }
4388
4389 d3dfmt_get_conv(This, FALSE /* We need color keying */, FALSE /* We won't use textures */, &desc, &convert);
4390
4391 /* The width is in 'length' not in bytes */
4392 width = This->currentDesc.Width;
4393 pitch = IWineD3DSurface_GetPitch(iface);
4394
4395 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4396 * but it isn't set (yet) in all cases it is getting called. */
4397 if ((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO))
4398 {
4399 struct wined3d_context *context = NULL;
4400
4401 TRACE("Removing the pbo attached to surface %p\n", This);
4402
4403 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4404 surface_remove_pbo(This, gl_info);
4405 if (context) context_release(context);
4406 }
4407
4408 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4409 int height = This->currentDesc.Height;
4410 byte_count = desc.conv_byte_count;
4411
4412 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4413 outpitch = width * byte_count;
4414 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4415
4416 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4417 if(!mem) {
4418 ERR("Out of memory %d, %d!\n", outpitch, height);
4419 return WINED3DERR_OUTOFVIDEOMEMORY;
4420 }
4421 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4422
4423 This->Flags |= SFLAG_CONVERTED;
4424 } else {
4425 This->Flags &= ~SFLAG_CONVERTED;
4426 mem = This->resource.allocatedMemory;
4427 byte_count = desc.byte_count;
4428 }
4429
4430 flush_to_framebuffer_drawpixels(This, desc.glFormat, desc.glType, byte_count, mem);
4431
4432 /* Don't delete PBO memory */
4433 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4434 HeapFree(GetProcessHeap(), 0, mem);
4435 }
4436 } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
4437 if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) {
4438 read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX);
4439 }
4440 else
4441 {
4442 /* Upload from system memory */
4443 BOOL srgb = flag == SFLAG_INSRGBTEX;
4444 struct wined3d_context *context = NULL;
4445
4446 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */,
4447 &desc, &convert);
4448
4449 if(srgb) {
4450 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) {
4451 /* Performance warning ... */
4452 FIXME("%p: Downloading rgb texture to reload it as srgb\n", This);
4453 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4454 }
4455 } else {
4456 if((This->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) {
4457 /* Performance warning ... */
4458 FIXME("%p: Downloading srgb texture to reload it as rgb\n", This);
4459 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4460 }
4461 }
4462 if(!(This->Flags & SFLAG_INSYSMEM)) {
4463 /* Should not happen */
4464 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
4465 /* Lets hope we get it from somewhere... */
4466 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4467 }
4468
4469 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4470
4471 surface_prepare_texture(This, gl_info, srgb);
4472 surface_bind_and_dirtify(This, srgb);
4473
4474 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
4475 This->Flags |= SFLAG_GLCKEY;
4476 This->glCKey = This->SrcBltCKey;
4477 }
4478 else This->Flags &= ~SFLAG_GLCKEY;
4479
4480 /* The width is in 'length' not in bytes */
4481 width = This->currentDesc.Width;
4482 pitch = IWineD3DSurface_GetPitch(iface);
4483
4484 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4485 * but it isn't set (yet) in all cases it is getting called. */
4486 if((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO)) {
4487 TRACE("Removing the pbo attached to surface %p\n", This);
4488 surface_remove_pbo(This, gl_info);
4489 }
4490
4491 if(desc.convert) {
4492 /* This code is entered for texture formats which need a fixup. */
4493 int height = This->currentDesc.Height;
4494
4495 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4496 outpitch = width * desc.conv_byte_count;
4497 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4498
4499 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4500 if(!mem) {
4501 ERR("Out of memory %d, %d!\n", outpitch, height);
4502 if (context) context_release(context);
4503 return WINED3DERR_OUTOFVIDEOMEMORY;
4504 }
4505 desc.convert(This->resource.allocatedMemory, mem, pitch, width, height);
4506 } else if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4507 /* This code is only entered for color keying fixups */
4508 int height = This->currentDesc.Height;
4509
4510 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4511 outpitch = width * desc.conv_byte_count;
4512 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4513
4514 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4515 if(!mem) {
4516 ERR("Out of memory %d, %d!\n", outpitch, height);
4517 if (context) context_release(context);
4518 return WINED3DERR_OUTOFVIDEOMEMORY;
4519 }
4520 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4521 } else {
4522 mem = This->resource.allocatedMemory;
4523 }
4524
4525 /* Make sure the correct pitch is used */
4526 ENTER_GL();
4527 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
4528 LEAVE_GL();
4529
4530 if (mem || (This->Flags & SFLAG_PBO))
4531 surface_upload_data(This, gl_info, &desc, srgb, mem);
4532
4533 /* Restore the default pitch */
4534 ENTER_GL();
4535 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4536 LEAVE_GL();
4537
4538 if (context) context_release(context);
4539
4540 /* Don't delete PBO memory */
4541 if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4542 HeapFree(GetProcessHeap(), 0, mem);
4543 }
4544 }
4545
4546 if(rect == NULL) {
4547 This->Flags |= flag;
4548 }
4549
4550 if (in_fbo && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
4551 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4552 This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4553 }
4554
4555 return WINED3D_OK;
4556}
4557
4558static HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container)
4559{
4560 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4561 IWineD3DSwapChain *swapchain = NULL;
4562
4563 /* Update the drawable size method */
4564 if(container) {
4565 IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
4566 }
4567 if(swapchain) {
4568 This->get_drawable_size = get_drawable_size_swapchain;
4569 IWineD3DSwapChain_Release(swapchain);
4570 } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4571 switch(wined3d_settings.offscreen_rendering_mode) {
4572 case ORM_FBO: This->get_drawable_size = get_drawable_size_fbo; break;
4573 case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4574 }
4575 }
4576
4577 return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
4578}
4579
4580static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
4581 return SURFACE_OPENGL;
4582}
4583
4584static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
4585 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4586 HRESULT hr;
4587
4588 /* If there's no destination surface there is nothing to do */
4589 if(!This->overlay_dest) return WINED3D_OK;
4590
4591 /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
4592 * update the overlay. Prevent an endless recursion
4593 */
4594 if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
4595 return WINED3D_OK;
4596 }
4597 This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
4598 hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
4599 iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
4600 NULL, WINED3DTEXF_LINEAR);
4601 This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
4602
4603 return hr;
4604}
4605
4606BOOL surface_is_offscreen(IWineD3DSurface *iface)
4607{
4608 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4609 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
4610
4611 /* Not on a swapchain - must be offscreen */
4612 if (!(This->Flags & SFLAG_SWAPCHAIN)) return TRUE;
4613
4614 /* The front buffer is always onscreen */
4615 if(iface == swapchain->frontBuffer) return FALSE;
4616
4617 /* If the swapchain is rendered to an FBO, the backbuffer is
4618 * offscreen, otherwise onscreen */
4619 return swapchain->render_to_fbo;
4620}
4621
4622const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
4623{
4624 /* IUnknown */
4625 IWineD3DBaseSurfaceImpl_QueryInterface,
4626 IWineD3DBaseSurfaceImpl_AddRef,
4627 IWineD3DSurfaceImpl_Release,
4628 /* IWineD3DResource */
4629 IWineD3DBaseSurfaceImpl_GetParent,
4630 IWineD3DBaseSurfaceImpl_SetPrivateData,
4631 IWineD3DBaseSurfaceImpl_GetPrivateData,
4632 IWineD3DBaseSurfaceImpl_FreePrivateData,
4633 IWineD3DBaseSurfaceImpl_SetPriority,
4634 IWineD3DBaseSurfaceImpl_GetPriority,
4635 IWineD3DSurfaceImpl_PreLoad,
4636 IWineD3DSurfaceImpl_UnLoad,
4637 IWineD3DBaseSurfaceImpl_GetType,
4638 /* IWineD3DSurface */
4639 IWineD3DBaseSurfaceImpl_GetContainer,
4640 IWineD3DBaseSurfaceImpl_GetDesc,
4641 IWineD3DSurfaceImpl_LockRect,
4642 IWineD3DSurfaceImpl_UnlockRect,
4643 IWineD3DSurfaceImpl_GetDC,
4644 IWineD3DSurfaceImpl_ReleaseDC,
4645 IWineD3DSurfaceImpl_Flip,
4646 IWineD3DSurfaceImpl_Blt,
4647 IWineD3DBaseSurfaceImpl_GetBltStatus,
4648 IWineD3DBaseSurfaceImpl_GetFlipStatus,
4649 IWineD3DBaseSurfaceImpl_IsLost,
4650 IWineD3DBaseSurfaceImpl_Restore,
4651 IWineD3DSurfaceImpl_BltFast,
4652 IWineD3DBaseSurfaceImpl_GetPalette,
4653 IWineD3DBaseSurfaceImpl_SetPalette,
4654 IWineD3DSurfaceImpl_RealizePalette,
4655 IWineD3DBaseSurfaceImpl_SetColorKey,
4656 IWineD3DBaseSurfaceImpl_GetPitch,
4657 IWineD3DSurfaceImpl_SetMem,
4658 IWineD3DBaseSurfaceImpl_SetOverlayPosition,
4659 IWineD3DBaseSurfaceImpl_GetOverlayPosition,
4660 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
4661 IWineD3DBaseSurfaceImpl_UpdateOverlay,
4662 IWineD3DBaseSurfaceImpl_SetClipper,
4663 IWineD3DBaseSurfaceImpl_GetClipper,
4664 /* Internal use: */
4665 IWineD3DSurfaceImpl_LoadTexture,
4666 IWineD3DSurfaceImpl_BindTexture,
4667 IWineD3DSurfaceImpl_SaveSnapshot,
4668 IWineD3DSurfaceImpl_SetContainer,
4669 IWineD3DBaseSurfaceImpl_GetData,
4670 IWineD3DSurfaceImpl_SetFormat,
4671 IWineD3DSurfaceImpl_PrivateSetup,
4672 IWineD3DSurfaceImpl_ModifyLocation,
4673 IWineD3DSurfaceImpl_LoadLocation,
4674 IWineD3DSurfaceImpl_GetImplType,
4675 IWineD3DSurfaceImpl_DrawOverlay
4676};
4677
4678static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
4679/* Context activation is done by the caller. */
4680static void ffp_blit_free(IWineD3DDevice *iface) { }
4681
4682/* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
4683/* Context activation is done by the caller. */
4684static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
4685{
4686 BYTE table[256][4];
4687 BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
4688
4689 d3dfmt_p8_init_palette(surface, table, colorkey_active);
4690
4691 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
4692 ENTER_GL();
4693 GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
4694 LEAVE_GL();
4695}
4696
4697/* Context activation is done by the caller. */
4698static HRESULT ffp_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4699{
4700 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4701 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4702 enum complex_fixup fixup = get_complex_fixup(surface->resource.format_desc->color_fixup);
4703
4704 /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
4705 * else the surface is converted in software at upload time in LoadLocation.
4706 */
4707 if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4708 ffp_blit_p8_upload_palette(surface, gl_info);
4709
4710 ENTER_GL();
4711 glEnable(surface->texture_target);
4712 checkGLcall("glEnable(surface->texture_target)");
4713 LEAVE_GL();
4714 return WINED3D_OK;
4715}
4716
4717/* Context activation is done by the caller. */
4718static void ffp_blit_unset(IWineD3DDevice *iface)
4719{
4720 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
4721 const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4722
4723 ENTER_GL();
4724 glDisable(GL_TEXTURE_2D);
4725 checkGLcall("glDisable(GL_TEXTURE_2D)");
4726 if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
4727 {
4728 glDisable(GL_TEXTURE_CUBE_MAP_ARB);
4729 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
4730 }
4731 if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
4732 {
4733 glDisable(GL_TEXTURE_RECTANGLE_ARB);
4734 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
4735 }
4736 LEAVE_GL();
4737}
4738
4739static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4740 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4741 const struct wined3d_format_desc *src_format_desc,
4742 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4743 const struct wined3d_format_desc *dst_format_desc)
4744{
4745 enum complex_fixup src_fixup;
4746
4747 if (blit_op == BLIT_OP_COLOR_FILL)
4748 {
4749 if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
4750 {
4751 TRACE("Color fill not supported\n");
4752 return FALSE;
4753 }
4754
4755 return TRUE;
4756 }
4757
4758 src_fixup = get_complex_fixup(src_format_desc->color_fixup);
4759 if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
4760 {
4761 TRACE("Checking support for fixup:\n");
4762 dump_color_fixup_desc(src_format_desc->color_fixup);
4763 }
4764
4765 if (blit_op != BLIT_OP_BLIT)
4766 {
4767 TRACE("Unsupported blit_op=%d\n", blit_op);
4768 return FALSE;
4769 }
4770
4771 if (!is_identity_fixup(dst_format_desc->color_fixup))
4772 {
4773 TRACE("Destination fixups are not supported\n");
4774 return FALSE;
4775 }
4776
4777 if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
4778 {
4779 TRACE("P8 fixup supported\n");
4780 return TRUE;
4781 }
4782
4783 /* We only support identity conversions. */
4784 if (is_identity_fixup(src_format_desc->color_fixup))
4785 {
4786 TRACE("[OK]\n");
4787 return TRUE;
4788 }
4789
4790 TRACE("[FAILED]\n");
4791 return FALSE;
4792}
4793
4794static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4795{
4796 return IWineD3DDeviceImpl_ClearSurface(device, dst_surface, 1 /* Number of rectangles */,
4797 (const WINED3DRECT*)dst_rect, WINED3DCLEAR_TARGET, fill_color, 0.0f /* Z */, 0 /* Stencil */);
4798}
4799
4800const struct blit_shader ffp_blit = {
4801 ffp_blit_alloc,
4802 ffp_blit_free,
4803 ffp_blit_set,
4804 ffp_blit_unset,
4805 ffp_blit_supported,
4806 ffp_blit_color_fill
4807};
4808
4809static HRESULT cpu_blit_alloc(IWineD3DDevice *iface)
4810{
4811 return WINED3D_OK;
4812}
4813
4814/* Context activation is done by the caller. */
4815static void cpu_blit_free(IWineD3DDevice *iface)
4816{
4817}
4818
4819/* Context activation is done by the caller. */
4820static HRESULT cpu_blit_set(IWineD3DDevice *iface, IWineD3DSurfaceImpl *surface)
4821{
4822 return WINED3D_OK;
4823}
4824
4825/* Context activation is done by the caller. */
4826static void cpu_blit_unset(IWineD3DDevice *iface)
4827{
4828}
4829
4830static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4831 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4832 const struct wined3d_format_desc *src_format_desc,
4833 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4834 const struct wined3d_format_desc *dst_format_desc)
4835{
4836 if (blit_op == BLIT_OP_COLOR_FILL)
4837 {
4838 return TRUE;
4839 }
4840
4841 return FALSE;
4842}
4843
4844static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect, DWORD fill_color)
4845{
4846 WINEDDBLTFX BltFx;
4847 memset(&BltFx, 0, sizeof(BltFx));
4848 BltFx.dwSize = sizeof(BltFx);
4849 BltFx.u5.dwFillColor = color_convert_argb_to_fmt(fill_color, dst_surface->resource.format_desc->format);
4850 return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
4851}
4852
4853const struct blit_shader cpu_blit = {
4854 cpu_blit_alloc,
4855 cpu_blit_free,
4856 cpu_blit_set,
4857 cpu_blit_unset,
4858 cpu_blit_supported,
4859 cpu_blit_color_fill
4860};
4861
4862static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum blit_operation blit_op,
4863 const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool,
4864 const struct wined3d_format_desc *src_format_desc,
4865 const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool,
4866 const struct wined3d_format_desc *dst_format_desc)
4867{
4868 if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
4869 return FALSE;
4870
4871 /* We only support blitting. Things like color keying / color fill should
4872 * be handled by other blitters.
4873 */
4874 if (blit_op != BLIT_OP_BLIT)
4875 return FALSE;
4876
4877 /* Source and/or destination need to be on the GL side */
4878 if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
4879 return FALSE;
4880
4881 if(!((src_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET))
4882 && ((dst_format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
4883 return FALSE;
4884
4885 if (!is_identity_fixup(src_format_desc->color_fixup) ||
4886 !is_identity_fixup(dst_format_desc->color_fixup))
4887 return FALSE;
4888
4889 if (!(src_format_desc->format == dst_format_desc->format
4890 || (is_identity_fixup(src_format_desc->color_fixup)
4891 && is_identity_fixup(dst_format_desc->color_fixup))))
4892 return FALSE;
4893
4894 return TRUE;
4895}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette