VirtualBox

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

Last change on this file since 16684 was 16477, checked in by vboxsync, 16 years ago

LGPL disclaimer by filemuncher

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

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