VirtualBox

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

Last change on this file since 38438 was 38331, checked in by vboxsync, 14 years ago

wddm/wine: fix winsat crashes (context adjustments for multiswapchains), basics for window creation inside wine

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

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