2 * IWineD3DSurface Implementation
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11 * Copyright 2007-2008 Henri Verbeet
12 * Copyright 2006-2008 Roderick Colenbrander
13 * Copyright 2009 Henri Verbeet for CodeWeavers
15 * This library is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU Lesser General Public
17 * License as published by the Free Software Foundation; either
18 * version 2.1 of the License, or (at your option) any later version.
20 * This library is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 * Lesser General Public License for more details.
25 * You should have received a copy of the GNU Lesser General Public
26 * License along with this library; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #include "wine/port.h"
32 #include "wined3d_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface
);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d
);
37 #define GLINFO_LOCATION (*gl_info)
39 static void surface_cleanup(IWineD3DSurfaceImpl
*This
)
41 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
42 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
43 struct wined3d_context
*context
= NULL
;
44 renderbuffer_entry_t
*entry
, *entry2
;
46 TRACE("(%p) : Cleaning up.\n", This
);
48 /* Need a context to destroy the texture. Use the currently active render
49 * target, but only if the primary render target exists. Otherwise
50 * lastActiveRenderTarget is garbage. When destroying the primary render
51 * target, Uninit3D() will activate a context before doing anything. */
52 if (device
->render_targets
&& device
->render_targets
[0])
54 context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
59 if (This
->texture_name
)
61 /* Release the OpenGL texture. */
62 TRACE("Deleting texture %u.\n", This
->texture_name
);
63 glDeleteTextures(1, &This
->texture_name
);
66 if (This
->Flags
& SFLAG_PBO
)
69 GL_EXTCALL(glDeleteBuffersARB(1, &This
->pbo
));
72 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &This
->renderbuffers
, renderbuffer_entry_t
, entry
)
74 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
75 HeapFree(GetProcessHeap(), 0, entry
);
80 if (This
->Flags
& SFLAG_DIBSECTION
)
83 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
85 /* Release the DIB section. */
86 DeleteObject(This
->dib
.DIBsection
);
87 This
->dib
.bitmap_data
= NULL
;
88 This
->resource
.allocatedMemory
= NULL
;
91 if (This
->Flags
& SFLAG_USERPTR
) IWineD3DSurface_SetMem((IWineD3DSurface
*)This
, NULL
);
92 if (This
->overlay_dest
) list_remove(&This
->overlay_entry
);
94 HeapFree(GetProcessHeap(), 0, This
->palette9
);
96 resource_cleanup((IWineD3DResource
*)This
);
98 if (context
) context_release(context
);
101 UINT
surface_calculate_size(const struct GlPixelFormatDesc
*format_desc
, UINT alignment
, UINT width
, UINT height
)
105 if (format_desc
->format
== WINED3DFMT_UNKNOWN
)
109 else if (format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
111 UINT row_block_count
= (width
+ format_desc
->block_width
- 1) / format_desc
->block_width
;
112 UINT row_count
= (height
+ format_desc
->block_height
- 1) / format_desc
->block_height
;
113 size
= row_count
* row_block_count
* format_desc
->block_byte_count
;
117 /* The pitch is a multiple of 4 bytes. */
118 size
= height
* (((width
* format_desc
->byte_count
) + alignment
- 1) & ~(alignment
- 1));
121 if (format_desc
->heightscale
!= 0.0f
) size
*= format_desc
->heightscale
;
126 HRESULT
surface_init(IWineD3DSurfaceImpl
*surface
, WINED3DSURFTYPE surface_type
, UINT alignment
,
127 UINT width
, UINT height
, UINT level
, BOOL lockable
, BOOL discard
, WINED3DMULTISAMPLE_TYPE multisample_type
,
128 UINT multisample_quality
, IWineD3DDeviceImpl
*device
, DWORD usage
, WINED3DFORMAT format
,
129 WINED3DPOOL pool
, IUnknown
*parent
, const struct wined3d_parent_ops
*parent_ops
)
131 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
132 const struct GlPixelFormatDesc
*format_desc
= getFormatDescEntry(format
, gl_info
);
133 void (*cleanup
)(IWineD3DSurfaceImpl
*This
);
134 unsigned int resource_size
;
137 if (multisample_quality
> 0)
139 FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality
);
140 multisample_quality
= 0;
143 /* FIXME: Check that the format is supported by the device. */
145 resource_size
= surface_calculate_size(format_desc
, alignment
, width
, height
);
147 /* Look at the implementation and set the correct Vtable. */
148 switch (surface_type
)
151 surface
->lpVtbl
= &IWineD3DSurface_Vtbl
;
152 cleanup
= surface_cleanup
;
156 surface
->lpVtbl
= &IWineGDISurface_Vtbl
;
157 cleanup
= surface_gdi_cleanup
;
161 ERR("Requested unknown surface implementation %#x.\n", surface_type
);
162 return WINED3DERR_INVALIDCALL
;
165 hr
= resource_init((IWineD3DResource
*)surface
, WINED3DRTYPE_SURFACE
,
166 device
, resource_size
, usage
, format_desc
, pool
, parent
, parent_ops
);
169 WARN("Failed to initialize resource, returning %#x.\n", hr
);
173 /* "Standalone" surface. */
174 IWineD3DSurface_SetContainer((IWineD3DSurface
*)surface
, NULL
);
176 surface
->currentDesc
.Width
= width
;
177 surface
->currentDesc
.Height
= height
;
178 surface
->currentDesc
.MultiSampleType
= multisample_type
;
179 surface
->currentDesc
.MultiSampleQuality
= multisample_quality
;
180 surface
->texture_level
= level
;
181 list_init(&surface
->overlays
);
184 surface
->Flags
= SFLAG_NORMCOORD
; /* Default to normalized coords. */
185 if (discard
) surface
->Flags
|= SFLAG_DISCARD
;
186 if (lockable
|| format
== WINED3DFMT_D16_LOCKABLE
) surface
->Flags
|= SFLAG_LOCKABLE
;
188 /* Quick lockable sanity check.
189 * TODO: remove this after surfaces, usage and lockability have been debugged properly
190 * this function is too deep to need to care about things like this.
191 * Levels need to be checked too, since they all affect what can be done. */
194 case WINED3DPOOL_SCRATCH
:
197 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
198 "which are mutually exclusive, setting lockable to TRUE.\n");
203 case WINED3DPOOL_SYSTEMMEM
:
205 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
208 case WINED3DPOOL_MANAGED
:
209 if (usage
& WINED3DUSAGE_DYNAMIC
)
210 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
213 case WINED3DPOOL_DEFAULT
:
214 if (lockable
&& !(usage
& (WINED3DUSAGE_DYNAMIC
| WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
215 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
219 FIXME("Unknown pool %#x.\n", pool
);
223 if (usage
& WINED3DUSAGE_RENDERTARGET
&& pool
!= WINED3DPOOL_DEFAULT
)
225 FIXME("Trying to create a render target that isn't in the default pool.\n");
228 /* Mark the texture as dirty so that it gets loaded first time around. */
229 surface_add_dirty_rect((IWineD3DSurface
*)surface
, NULL
);
230 list_init(&surface
->renderbuffers
);
232 TRACE("surface %p, memory %p, size %u\n", surface
, surface
->resource
.allocatedMemory
, surface
->resource
.size
);
234 /* Call the private setup routine */
235 hr
= IWineD3DSurface_PrivateSetup((IWineD3DSurface
*)surface
);
238 ERR("Private setup failed, returning %#x\n", hr
);
246 static void surface_force_reload(IWineD3DSurface
*iface
)
248 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
250 This
->Flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
253 void surface_set_texture_name(IWineD3DSurface
*iface
, GLuint new_name
, BOOL srgb
)
255 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
261 name
= &This
->texture_name_srgb
;
262 flag
= SFLAG_INSRGBTEX
;
266 name
= &This
->texture_name
;
267 flag
= SFLAG_INTEXTURE
;
270 TRACE("(%p) : setting texture name %u\n", This
, new_name
);
272 if (!*name
&& new_name
)
274 /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
275 * surface has no texture name yet. See if we can get rid of this. */
276 if (This
->Flags
& flag
)
277 ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n");
278 IWineD3DSurface_ModifyLocation(iface
, flag
, FALSE
);
282 surface_force_reload(iface
);
285 void surface_set_texture_target(IWineD3DSurface
*iface
, GLenum target
)
287 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
289 TRACE("(%p) : setting target %#x\n", This
, target
);
291 if (This
->texture_target
!= target
)
293 if (target
== GL_TEXTURE_RECTANGLE_ARB
)
295 This
->Flags
&= ~SFLAG_NORMCOORD
;
297 else if (This
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
299 This
->Flags
|= SFLAG_NORMCOORD
;
302 This
->texture_target
= target
;
303 surface_force_reload(iface
);
306 /* Context activation is done by the caller. */
307 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl
*This
, BOOL srgb
) {
308 DWORD active_sampler
;
310 /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
311 * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
312 * gl states. The current texture unit should always be a valid one.
314 * To be more specific, this is tricky because we can implicitly be called
315 * from sampler() in state.c. This means we can't touch anything other than
316 * whatever happens to be the currently active texture, or we would risk
317 * marking already applied sampler states dirty again.
319 * TODO: Track the current active texture per GL context instead of using glGet
321 GLint active_texture
;
323 glGetIntegerv(GL_ACTIVE_TEXTURE
, &active_texture
);
325 active_sampler
= This
->resource
.device
->rev_tex_unit_map
[active_texture
- GL_TEXTURE0_ARB
];
327 if (active_sampler
!= WINED3D_UNMAPPED_STAGE
)
329 IWineD3DDeviceImpl_MarkStateDirty(This
->resource
.device
, STATE_SAMPLER(active_sampler
));
331 IWineD3DSurface_BindTexture((IWineD3DSurface
*)This
, srgb
);
334 /* This function checks if the primary render target uses the 8bit paletted format. */
335 static BOOL
primary_render_target_is_p8(IWineD3DDeviceImpl
*device
)
337 if (device
->render_targets
&& device
->render_targets
[0]) {
338 IWineD3DSurfaceImpl
* render_target
= (IWineD3DSurfaceImpl
*)device
->render_targets
[0];
339 if ((render_target
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
340 && (render_target
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
))
346 #undef GLINFO_LOCATION
348 #define GLINFO_LOCATION This->resource.device->adapter->gl_info
350 /* This call just downloads data, the caller is responsible for binding the
351 * correct texture. */
352 /* Context activation is done by the caller. */
353 static void surface_download_data(IWineD3DSurfaceImpl
*This
) {
354 const struct GlPixelFormatDesc
*format_desc
= This
->resource
.format_desc
;
356 /* Only support read back of converted P8 surfaces */
357 if (This
->Flags
& SFLAG_CONVERTED
&& format_desc
->format
!= WINED3DFMT_P8_UINT
)
359 FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc
->format
));
365 if (format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
367 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
368 This
, This
->texture_level
, format_desc
->glFormat
, format_desc
->glType
,
369 This
->resource
.allocatedMemory
);
371 if (This
->Flags
& SFLAG_PBO
)
373 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, This
->pbo
));
374 checkGLcall("glBindBufferARB");
375 GL_EXTCALL(glGetCompressedTexImageARB(This
->texture_target
, This
->texture_level
, NULL
));
376 checkGLcall("glGetCompressedTexImageARB");
377 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
378 checkGLcall("glBindBufferARB");
382 GL_EXTCALL(glGetCompressedTexImageARB(This
->texture_target
,
383 This
->texture_level
, This
->resource
.allocatedMemory
));
384 checkGLcall("glGetCompressedTexImageARB");
390 GLenum format
= format_desc
->glFormat
;
391 GLenum type
= format_desc
->glType
;
395 /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
396 if (format_desc
->format
== WINED3DFMT_P8_UINT
&& primary_render_target_is_p8(This
->resource
.device
))
399 type
= GL_UNSIGNED_BYTE
;
402 if (This
->Flags
& SFLAG_NONPOW2
) {
403 unsigned char alignment
= This
->resource
.device
->surface_alignment
;
404 src_pitch
= format_desc
->byte_count
* This
->pow2Width
;
405 dst_pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
);
406 src_pitch
= (src_pitch
+ alignment
- 1) & ~(alignment
- 1);
407 mem
= HeapAlloc(GetProcessHeap(), 0, src_pitch
* This
->pow2Height
);
409 mem
= This
->resource
.allocatedMemory
;
412 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
413 This
, This
->texture_level
, format
, type
, mem
);
415 if(This
->Flags
& SFLAG_PBO
) {
416 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, This
->pbo
));
417 checkGLcall("glBindBufferARB");
419 glGetTexImage(This
->texture_target
, This
->texture_level
, format
, type
, NULL
);
420 checkGLcall("glGetTexImage");
422 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
423 checkGLcall("glBindBufferARB");
425 glGetTexImage(This
->texture_target
, This
->texture_level
, format
, type
, mem
);
426 checkGLcall("glGetTexImage");
430 if (This
->Flags
& SFLAG_NONPOW2
) {
431 const BYTE
*src_data
;
435 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
436 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
437 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
439 * We're doing this...
441 * instead of boxing the texture :
442 * |<-texture width ->| -->pow2width| /\
443 * |111111111111111111| | |
444 * |222 Texture 222222| boxed empty | texture height
445 * |3333 Data 33333333| | |
446 * |444444444444444444| | \/
447 * ----------------------------------- |
448 * | boxed empty | boxed empty | pow2height
450 * -----------------------------------
453 * we're repacking the data to the expected texture width
455 * |<-texture width ->| -->pow2width| /\
456 * |111111111111111111222222222222222| |
457 * |222333333333333333333444444444444| texture height
461 * | empty | pow2height
463 * -----------------------------------
467 * |<-texture width ->| /\
468 * |111111111111111111|
469 * |222222222222222222|texture height
470 * |333333333333333333|
471 * |444444444444444444| \/
472 * --------------------
474 * this also means that any references to allocatedMemory should work with the data as if were a
475 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
477 * internally the texture is still stored in a boxed format so any references to textureName will
478 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
480 * Performance should not be an issue, because applications normally do not lock the surfaces when
481 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
482 * and doesn't have to be re-read.
485 dst_data
= This
->resource
.allocatedMemory
;
486 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This
, src_pitch
, dst_pitch
);
487 for (y
= 1 ; y
< This
->currentDesc
.Height
; y
++) {
488 /* skip the first row */
489 src_data
+= src_pitch
;
490 dst_data
+= dst_pitch
;
491 memcpy(dst_data
, src_data
, dst_pitch
);
494 HeapFree(GetProcessHeap(), 0, mem
);
498 /* Surface has now been downloaded */
499 This
->Flags
|= SFLAG_INSYSMEM
;
502 /* This call just uploads data, the caller is responsible for binding the
503 * correct texture. */
504 /* Context activation is done by the caller. */
505 static void surface_upload_data(IWineD3DSurfaceImpl
*This
, GLenum internal
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
, const GLvoid
*data
) {
506 const struct GlPixelFormatDesc
*format_desc
= This
->resource
.format_desc
;
508 TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
509 This
, internal
, width
, height
, format
, type
, data
);
510 TRACE("target %#x, level %u, resource size %u.\n",
511 This
->texture_target
, This
->texture_level
, This
->resource
.size
);
513 if (format_desc
->heightscale
!= 1.0f
&& format_desc
->heightscale
!= 0.0f
) height
*= format_desc
->heightscale
;
517 if (This
->Flags
& SFLAG_PBO
)
519 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
520 checkGLcall("glBindBufferARB");
522 TRACE("(%p) pbo: %#x, data: %p.\n", This
, This
->pbo
, data
);
526 if (format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
528 TRACE("Calling glCompressedTexSubImage2DARB.\n");
530 GL_EXTCALL(glCompressedTexSubImage2DARB(This
->texture_target
, This
->texture_level
,
531 0, 0, width
, height
, internal
, This
->resource
.size
, data
));
532 checkGLcall("glCompressedTexSubImage2DARB");
536 TRACE("Calling glTexSubImage2D.\n");
538 glTexSubImage2D(This
->texture_target
, This
->texture_level
,
539 0, 0, width
, height
, format
, type
, data
);
540 checkGLcall("glTexSubImage2D");
543 if (This
->Flags
& SFLAG_PBO
)
545 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
546 checkGLcall("glBindBufferARB");
552 /* This call just allocates the texture, the caller is responsible for binding
553 * the correct texture. */
554 /* Context activation is done by the caller. */
555 static void surface_allocate_surface(IWineD3DSurfaceImpl
*This
, GLenum internal
, GLsizei width
, GLsizei height
, GLenum format
, GLenum type
) {
556 const struct wined3d_gl_info
*gl_info
= &This
->resource
.device
->adapter
->gl_info
;
557 const struct GlPixelFormatDesc
*format_desc
= This
->resource
.format_desc
;
558 BOOL enable_client_storage
= FALSE
;
559 const BYTE
*mem
= NULL
;
561 if (format_desc
->heightscale
!= 1.0f
&& format_desc
->heightscale
!= 0.0f
) height
*= format_desc
->heightscale
;
563 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",
564 This
, This
->texture_target
, This
->texture_level
, debug_d3dformat(format_desc
->format
),
565 internal
, width
, height
, format
, type
);
569 if (gl_info
->supported
[APPLE_CLIENT_STORAGE
])
571 if(This
->Flags
& (SFLAG_NONPOW2
| SFLAG_DIBSECTION
| SFLAG_OVERSIZE
| SFLAG_CONVERTED
) || This
->resource
.allocatedMemory
== NULL
) {
572 /* In some cases we want to disable client storage.
573 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
574 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
575 * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory
576 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
577 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
579 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
580 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
581 This
->Flags
&= ~SFLAG_CLIENT
;
582 enable_client_storage
= TRUE
;
584 This
->Flags
|= SFLAG_CLIENT
;
586 /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
587 * it might point into a pbo. Instead use heapMemory, but get the alignment right.
589 mem
= (BYTE
*)(((ULONG_PTR
) This
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
593 if (format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
&& mem
)
595 GL_EXTCALL(glCompressedTexImage2DARB(This
->texture_target
, This
->texture_level
,
596 internal
, width
, height
, 0, This
->resource
.size
, mem
));
600 glTexImage2D(This
->texture_target
, This
->texture_level
,
601 internal
, width
, height
, 0, format
, type
, mem
);
602 checkGLcall("glTexImage2D");
605 if(enable_client_storage
) {
606 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
607 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
612 /* In D3D the depth stencil dimensions have to be greater than or equal to the
613 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
614 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
615 /* GL locking is done by the caller */
616 void surface_set_compatible_renderbuffer(IWineD3DSurface
*iface
, unsigned int width
, unsigned int height
) {
617 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
618 const struct wined3d_gl_info
*gl_info
= &This
->resource
.device
->adapter
->gl_info
;
619 renderbuffer_entry_t
*entry
;
620 GLuint renderbuffer
= 0;
621 unsigned int src_width
, src_height
;
623 src_width
= This
->pow2Width
;
624 src_height
= This
->pow2Height
;
626 /* A depth stencil smaller than the render target is not valid */
627 if (width
> src_width
|| height
> src_height
) return;
629 /* Remove any renderbuffer set if the sizes match */
630 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
631 || (width
== src_width
&& height
== src_height
))
633 This
->current_renderbuffer
= NULL
;
637 /* Look if we've already got a renderbuffer of the correct dimensions */
638 LIST_FOR_EACH_ENTRY(entry
, &This
->renderbuffers
, renderbuffer_entry_t
, entry
) {
639 if (entry
->width
== width
&& entry
->height
== height
) {
640 renderbuffer
= entry
->id
;
641 This
->current_renderbuffer
= entry
;
647 gl_info
->fbo_ops
.glGenRenderbuffers(1, &renderbuffer
);
648 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, renderbuffer
);
649 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
,
650 This
->resource
.format_desc
->glInternal
, width
, height
);
652 entry
= HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t
));
653 entry
->width
= width
;
654 entry
->height
= height
;
655 entry
->id
= renderbuffer
;
656 list_add_head(&This
->renderbuffers
, &entry
->entry
);
658 This
->current_renderbuffer
= entry
;
661 checkGLcall("set_compatible_renderbuffer");
664 GLenum
surface_get_gl_buffer(IWineD3DSurface
*iface
)
666 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
667 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*)This
->container
;
669 TRACE("iface %p.\n", iface
);
671 if (!(This
->Flags
& SFLAG_SWAPCHAIN
))
673 ERR("Surface %p is not on a swapchain.\n", iface
);
677 if (swapchain
->backBuffer
&& swapchain
->backBuffer
[0] == iface
)
679 if (swapchain
->render_to_fbo
)
681 TRACE("Returning GL_COLOR_ATTACHMENT0\n");
682 return GL_COLOR_ATTACHMENT0
;
684 TRACE("Returning GL_BACK\n");
687 else if (swapchain
->frontBuffer
== iface
)
689 TRACE("Returning GL_FRONT\n");
693 FIXME("Higher back buffer, returning GL_BACK\n");
697 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
698 void surface_add_dirty_rect(IWineD3DSurface
*iface
, const RECT
*dirty_rect
)
700 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
701 IWineD3DBaseTexture
*baseTexture
= NULL
;
703 if (!(This
->Flags
& SFLAG_INSYSMEM
) && (This
->Flags
& SFLAG_INTEXTURE
))
704 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
/* no partial locking for textures yet */);
706 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, TRUE
);
709 This
->dirtyRect
.left
= min(This
->dirtyRect
.left
, dirty_rect
->left
);
710 This
->dirtyRect
.top
= min(This
->dirtyRect
.top
, dirty_rect
->top
);
711 This
->dirtyRect
.right
= max(This
->dirtyRect
.right
, dirty_rect
->right
);
712 This
->dirtyRect
.bottom
= max(This
->dirtyRect
.bottom
, dirty_rect
->bottom
);
716 This
->dirtyRect
.left
= 0;
717 This
->dirtyRect
.top
= 0;
718 This
->dirtyRect
.right
= This
->currentDesc
.Width
;
719 This
->dirtyRect
.bottom
= This
->currentDesc
.Height
;
722 TRACE("(%p) : Dirty: yes, Rect:(%d, %d, %d, %d)\n", This
, This
->dirtyRect
.left
,
723 This
->dirtyRect
.top
, This
->dirtyRect
.right
, This
->dirtyRect
.bottom
);
725 /* if the container is a basetexture then mark it dirty. */
726 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
)))
728 TRACE("Passing to container\n");
729 IWineD3DBaseTexture_SetDirty(baseTexture
, TRUE
);
730 IWineD3DBaseTexture_Release(baseTexture
);
734 static inline BOOL
surface_can_stretch_rect(IWineD3DSurfaceImpl
*src
, IWineD3DSurfaceImpl
*dst
)
736 return ((src
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
)
737 || (src
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
738 && ((dst
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_FBO_ATTACHABLE
)
739 || (dst
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
))
740 && (src
->resource
.format_desc
->format
== dst
->resource
.format_desc
->format
741 || (is_identity_fixup(src
->resource
.format_desc
->color_fixup
)
742 && is_identity_fixup(dst
->resource
.format_desc
->color_fixup
)));
745 static ULONG WINAPI
IWineD3DSurfaceImpl_Release(IWineD3DSurface
*iface
)
747 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
748 ULONG ref
= InterlockedDecrement(&This
->resource
.ref
);
749 TRACE("(%p) : Releasing from %d\n", This
, ref
+ 1);
753 surface_cleanup(This
);
754 This
->resource
.parent_ops
->wined3d_object_destroyed(This
->resource
.parent
);
756 TRACE("(%p) Released.\n", This
);
757 HeapFree(GetProcessHeap(), 0, This
);
763 /* ****************************************************
764 IWineD3DSurface IWineD3DResource parts follow
765 **************************************************** */
767 void surface_internal_preload(IWineD3DSurface
*iface
, enum WINED3DSRGB srgb
)
769 /* TODO: check for locks */
770 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
771 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
772 IWineD3DBaseTexture
*baseTexture
= NULL
;
774 TRACE("(%p)Checking to see if the container is a base texture\n", This
);
775 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
776 IWineD3DBaseTextureImpl
*tex_impl
= (IWineD3DBaseTextureImpl
*) baseTexture
;
777 TRACE("Passing to container\n");
778 tex_impl
->baseTexture
.internal_preload(baseTexture
, srgb
);
779 IWineD3DBaseTexture_Release(baseTexture
);
781 struct wined3d_context
*context
= NULL
;
783 TRACE("(%p) : About to load surface\n", This
);
785 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
787 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
788 || This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
)
790 if(palette9_changed(This
)) {
791 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
792 /* TODO: This is not necessarily needed with hw palettized texture support */
793 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
);
794 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
795 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INTEXTURE
, FALSE
);
799 IWineD3DSurface_LoadTexture(iface
, srgb
== SRGB_SRGB
? TRUE
: FALSE
);
801 if (This
->resource
.pool
== WINED3DPOOL_DEFAULT
) {
802 /* Tell opengl to try and keep this texture in video ram (well mostly) */
806 glPrioritizeTextures(1, &This
->texture_name
, &tmp
);
810 if (context
) context_release(context
);
815 static void WINAPI
IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface
*iface
) {
816 surface_internal_preload(iface
, SRGB_ANY
);
819 /* Context activation is done by the caller. */
820 static void surface_remove_pbo(IWineD3DSurfaceImpl
*This
) {
821 This
->resource
.heapMemory
= HeapAlloc(GetProcessHeap() ,0 , This
->resource
.size
+ RESOURCE_ALIGNMENT
);
822 This
->resource
.allocatedMemory
=
823 (BYTE
*)(((ULONG_PTR
) This
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
826 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
827 checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
828 GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0, This
->resource
.size
, This
->resource
.allocatedMemory
));
829 checkGLcall("glGetBufferSubDataARB");
830 GL_EXTCALL(glDeleteBuffersARB(1, &This
->pbo
));
831 checkGLcall("glDeleteBuffersARB");
835 This
->Flags
&= ~SFLAG_PBO
;
838 BOOL
surface_init_sysmem(IWineD3DSurface
*iface
)
840 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
842 if(!This
->resource
.allocatedMemory
)
844 This
->resource
.heapMemory
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, This
->resource
.size
+ RESOURCE_ALIGNMENT
);
845 if(!This
->resource
.heapMemory
)
847 ERR("Out of memory\n");
850 This
->resource
.allocatedMemory
=
851 (BYTE
*)(((ULONG_PTR
) This
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
855 memset(This
->resource
.allocatedMemory
, 0, This
->resource
.size
);
858 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, TRUE
);
862 static void WINAPI
IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface
*iface
) {
863 IWineD3DBaseTexture
*texture
= NULL
;
864 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
865 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
866 const struct wined3d_gl_info
*gl_info
;
867 renderbuffer_entry_t
*entry
, *entry2
;
868 struct wined3d_context
*context
;
870 TRACE("(%p)\n", iface
);
872 if(This
->resource
.pool
== WINED3DPOOL_DEFAULT
) {
873 /* Default pool resources are supposed to be destroyed before Reset is called.
874 * Implicit resources stay however. So this means we have an implicit render target
875 * or depth stencil. The content may be destroyed, but we still have to tear down
876 * opengl resources, so we cannot leave early.
878 * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
879 * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
880 * or the depth stencil into an FBO the texture or render buffer will be removed
881 * and all flags get lost
883 surface_init_sysmem(iface
);
885 /* Load the surface into system memory */
886 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
);
887 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INDRAWABLE
, FALSE
);
889 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INTEXTURE
, FALSE
);
890 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSRGBTEX
, FALSE
);
891 This
->Flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
893 context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
894 gl_info
= context
->gl_info
;
896 /* Destroy PBOs, but load them into real sysmem before */
897 if(This
->Flags
& SFLAG_PBO
) {
898 surface_remove_pbo(This
);
901 /* Destroy fbo render buffers. This is needed for implicit render targets, for
902 * all application-created targets the application has to release the surface
903 * before calling _Reset
905 LIST_FOR_EACH_ENTRY_SAFE(entry
, entry2
, &This
->renderbuffers
, renderbuffer_entry_t
, entry
) {
907 gl_info
->fbo_ops
.glDeleteRenderbuffers(1, &entry
->id
);
909 list_remove(&entry
->entry
);
910 HeapFree(GetProcessHeap(), 0, entry
);
912 list_init(&This
->renderbuffers
);
913 This
->current_renderbuffer
= NULL
;
915 /* If we're in a texture, the texture name belongs to the texture. Otherwise,
918 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **) &texture
);
921 glDeleteTextures(1, &This
->texture_name
);
922 This
->texture_name
= 0;
923 glDeleteTextures(1, &This
->texture_name_srgb
);
924 This
->texture_name_srgb
= 0;
927 IWineD3DBaseTexture_Release(texture
);
930 context_release(context
);
935 /* ******************************************************
936 IWineD3DSurface IWineD3DSurface parts follow
937 ****************************************************** */
939 /* Read the framebuffer back into the surface */
940 static void read_from_framebuffer(IWineD3DSurfaceImpl
*This
, const RECT
*rect
, void *dest
, UINT pitch
)
942 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
943 struct wined3d_context
*context
;
947 BYTE
*row
, *top
, *bottom
;
951 BOOL srcIsUpsideDown
;
956 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
957 static BOOL warned
= FALSE
;
959 ERR("The application tries to lock the render target, but render target locking is disabled\n");
965 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
966 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
967 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
968 * context->last_was_blit set on the unlock.
970 context
= context_acquire(myDevice
, (IWineD3DSurface
*) This
, CTXUSAGE_BLIT
);
973 /* Select the correct read buffer, and give some debug output.
974 * There is no need to keep track of the current read buffer or reset it, every part of the code
975 * that reads sets the read buffer as desired.
977 if (surface_is_offscreen((IWineD3DSurface
*) This
))
979 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
980 * Read from the back buffer
982 TRACE("Locking offscreen render target\n");
983 glReadBuffer(myDevice
->offscreenBuffer
);
984 srcIsUpsideDown
= TRUE
;
988 /* Onscreen surfaces are always part of a swapchain */
989 GLenum buffer
= surface_get_gl_buffer((IWineD3DSurface
*)This
);
990 TRACE("Locking %#x buffer\n", buffer
);
991 glReadBuffer(buffer
);
992 checkGLcall("glReadBuffer");
993 srcIsUpsideDown
= FALSE
;
996 /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1000 local_rect
.right
= This
->currentDesc
.Width
;
1001 local_rect
.bottom
= This
->currentDesc
.Height
;
1005 /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1007 switch(This
->resource
.format_desc
->format
)
1009 case WINED3DFMT_P8_UINT
:
1011 if(primary_render_target_is_p8(myDevice
)) {
1012 /* In case of P8 render targets the index is stored in the alpha component */
1014 type
= GL_UNSIGNED_BYTE
;
1016 bpp
= This
->resource
.format_desc
->byte_count
;
1018 /* GL can't return palettized data, so read ARGB pixels into a
1019 * separate block of memory and convert them into palettized format
1020 * in software. Slow, but if the app means to use palettized render
1021 * targets and locks it...
1023 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1024 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1025 * for the color channels when palettizing the colors.
1028 type
= GL_UNSIGNED_BYTE
;
1030 mem
= HeapAlloc(GetProcessHeap(), 0, This
->resource
.size
* 3);
1032 ERR("Out of memory\n");
1036 bpp
= This
->resource
.format_desc
->byte_count
* 3;
1043 fmt
= This
->resource
.format_desc
->glFormat
;
1044 type
= This
->resource
.format_desc
->glType
;
1045 bpp
= This
->resource
.format_desc
->byte_count
;
1048 if(This
->Flags
& SFLAG_PBO
) {
1049 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, This
->pbo
));
1050 checkGLcall("glBindBufferARB");
1052 ERR("mem not null for pbo -- unexpected\n");
1057 /* Save old pixel store pack state */
1058 glGetIntegerv(GL_PACK_ROW_LENGTH
, &rowLen
);
1059 checkGLcall("glGetIntegerv");
1060 glGetIntegerv(GL_PACK_SKIP_PIXELS
, &skipPix
);
1061 checkGLcall("glGetIntegerv");
1062 glGetIntegerv(GL_PACK_SKIP_ROWS
, &skipRow
);
1063 checkGLcall("glGetIntegerv");
1065 /* Setup pixel store pack state -- to glReadPixels into the correct place */
1066 glPixelStorei(GL_PACK_ROW_LENGTH
, This
->currentDesc
.Width
);
1067 checkGLcall("glPixelStorei");
1068 glPixelStorei(GL_PACK_SKIP_PIXELS
, local_rect
.left
);
1069 checkGLcall("glPixelStorei");
1070 glPixelStorei(GL_PACK_SKIP_ROWS
, local_rect
.top
);
1071 checkGLcall("glPixelStorei");
1073 glReadPixels(local_rect
.left
, (!srcIsUpsideDown
) ? (This
->currentDesc
.Height
- local_rect
.bottom
) : local_rect
.top
,
1074 local_rect
.right
- local_rect
.left
,
1075 local_rect
.bottom
- local_rect
.top
,
1077 checkGLcall("glReadPixels");
1079 /* Reset previous pixel store pack state */
1080 glPixelStorei(GL_PACK_ROW_LENGTH
, rowLen
);
1081 checkGLcall("glPixelStorei");
1082 glPixelStorei(GL_PACK_SKIP_PIXELS
, skipPix
);
1083 checkGLcall("glPixelStorei");
1084 glPixelStorei(GL_PACK_SKIP_ROWS
, skipRow
);
1085 checkGLcall("glPixelStorei");
1087 if(This
->Flags
& SFLAG_PBO
) {
1088 GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB
, 0));
1089 checkGLcall("glBindBufferARB");
1091 /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1092 * to get a pointer to it and perform the flipping in software. This is a lot
1093 * faster than calling glReadPixels for each line. In case we want more speed
1094 * we should rerender it flipped in a FBO and read the data back from the FBO. */
1095 if(!srcIsUpsideDown
) {
1096 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
1097 checkGLcall("glBindBufferARB");
1099 mem
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
1100 checkGLcall("glMapBufferARB");
1104 /* TODO: Merge this with the palettization loop below for P8 targets */
1105 if(!srcIsUpsideDown
) {
1107 /* glReadPixels returns the image upside down, and there is no way to prevent this.
1108 Flip the lines in software */
1109 len
= (local_rect
.right
- local_rect
.left
) * bpp
;
1110 off
= local_rect
.left
* bpp
;
1112 row
= HeapAlloc(GetProcessHeap(), 0, len
);
1114 ERR("Out of memory\n");
1115 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
) HeapFree(GetProcessHeap(), 0, mem
);
1120 top
= mem
+ pitch
* local_rect
.top
;
1121 bottom
= mem
+ pitch
* (local_rect
.bottom
- 1);
1122 for(i
= 0; i
< (local_rect
.bottom
- local_rect
.top
) / 2; i
++) {
1123 memcpy(row
, top
+ off
, len
);
1124 memcpy(top
+ off
, bottom
+ off
, len
);
1125 memcpy(bottom
+ off
, row
, len
);
1129 HeapFree(GetProcessHeap(), 0, row
);
1131 /* Unmap the temp PBO buffer */
1132 if(This
->Flags
& SFLAG_PBO
) {
1133 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
1134 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1139 context_release(context
);
1141 /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1142 * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1143 * the same color but we have no choice.
1144 * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1146 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
&& !primary_render_target_is_p8(myDevice
))
1148 const PALETTEENTRY
*pal
= NULL
;
1149 DWORD width
= pitch
/ 3;
1153 pal
= This
->palette
->palents
;
1155 ERR("Palette is missing, cannot perform inverse palette lookup\n");
1156 HeapFree(GetProcessHeap(), 0, mem
);
1160 for(y
= local_rect
.top
; y
< local_rect
.bottom
; y
++) {
1161 for(x
= local_rect
.left
; x
< local_rect
.right
; x
++) {
1162 /* start lines pixels */
1163 const BYTE
*blue
= mem
+ y
* pitch
+ x
* (sizeof(BYTE
) * 3);
1164 const BYTE
*green
= blue
+ 1;
1165 const BYTE
*red
= green
+ 1;
1167 for(c
= 0; c
< 256; c
++) {
1168 if(*red
== pal
[c
].peRed
&&
1169 *green
== pal
[c
].peGreen
&&
1170 *blue
== pal
[c
].peBlue
)
1172 *((BYTE
*) dest
+ y
* width
+ x
) = c
;
1178 HeapFree(GetProcessHeap(), 0, mem
);
1182 /* Read the framebuffer contents into a texture */
1183 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl
*This
, BOOL srgb
)
1185 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
1186 struct wined3d_context
*context
;
1188 GLenum format
, internal
, type
;
1189 CONVERT_TYPES convert
;
1191 BOOL alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
1193 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, TRUE
/* We will use textures */, &format
, &internal
, &type
, &convert
, &bpp
, srgb
);
1195 /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1196 * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1197 * states in the stateblock, and no driver was found yet that had bugs in that regard.
1199 context
= context_acquire(device
, (IWineD3DSurface
*) This
, CTXUSAGE_RESOURCELOAD
);
1200 surface_bind_and_dirtify(This
, srgb
);
1203 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
1206 /* Select the correct read buffer, and give some debug output.
1207 * There is no need to keep track of the current read buffer or reset it, every part of the code
1208 * that reads sets the read buffer as desired.
1210 if (!surface_is_offscreen((IWineD3DSurface
*)This
))
1212 GLenum buffer
= surface_get_gl_buffer((IWineD3DSurface
*)This
);
1213 TRACE("Locking %#x buffer\n", buffer
);
1216 glReadBuffer(buffer
);
1217 checkGLcall("glReadBuffer");
1222 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1223 * Read from the back buffer
1225 TRACE("Locking offscreen render target\n");
1227 glReadBuffer(device
->offscreenBuffer
);
1228 checkGLcall("glReadBuffer");
1232 if(!(This
->Flags
& alloc_flag
)) {
1233 surface_allocate_surface(This
, internal
, This
->pow2Width
,
1234 This
->pow2Height
, format
, type
);
1235 This
->Flags
|= alloc_flag
;
1239 /* If !SrcIsUpsideDown we should flip the surface.
1240 * This can be done using glCopyTexSubImage2D but this
1241 * is VERY slow, so don't do that. We should prevent
1242 * this code from getting called in such cases or perhaps
1243 * we can use FBOs */
1245 glCopyTexSubImage2D(This
->texture_target
, This
->texture_level
,
1246 0, 0, 0, 0, This
->currentDesc
.Width
, This
->currentDesc
.Height
);
1247 checkGLcall("glCopyTexSubImage2D");
1249 glReadBuffer(prevRead
);
1250 checkGLcall("glReadBuffer");
1254 context_release(context
);
1256 TRACE("Updated target %d\n", This
->texture_target
);
1259 static void surface_prepare_system_memory(IWineD3DSurfaceImpl
*This
)
1261 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
1262 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1264 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1265 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1268 if(!(This
->Flags
& SFLAG_DYNLOCK
)) {
1270 /* MAXLOCKCOUNT is defined in wined3d_private.h */
1271 if(This
->lockCount
> MAXLOCKCOUNT
) {
1272 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1273 This
->Flags
|= SFLAG_DYNLOCK
;
1277 /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1278 * Also don't create a PBO for systemmem surfaces.
1280 if (gl_info
->supported
[ARB_PIXEL_BUFFER_OBJECT
] && (This
->Flags
& SFLAG_DYNLOCK
)
1281 && !(This
->Flags
& (SFLAG_PBO
| SFLAG_CONVERTED
| SFLAG_NONPOW2
))
1282 && (This
->resource
.pool
!= WINED3DPOOL_SYSTEMMEM
))
1285 struct wined3d_context
*context
;
1287 context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
1290 GL_EXTCALL(glGenBuffersARB(1, &This
->pbo
));
1291 error
= glGetError();
1292 if(This
->pbo
== 0 || error
!= GL_NO_ERROR
) {
1293 ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error
), error
);
1296 TRACE("Attaching pbo=%#x to (%p)\n", This
->pbo
, This
);
1298 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
1299 checkGLcall("glBindBufferARB");
1301 GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->resource
.size
+ 4, This
->resource
.allocatedMemory
, GL_STREAM_DRAW_ARB
));
1302 checkGLcall("glBufferDataARB");
1304 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1305 checkGLcall("glBindBufferARB");
1307 /* We don't need the system memory anymore and we can't even use it for PBOs */
1308 if(!(This
->Flags
& SFLAG_CLIENT
)) {
1309 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
1310 This
->resource
.heapMemory
= NULL
;
1312 This
->resource
.allocatedMemory
= NULL
;
1313 This
->Flags
|= SFLAG_PBO
;
1315 context_release(context
);
1317 else if (!(This
->resource
.allocatedMemory
|| This
->Flags
& SFLAG_PBO
))
1319 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1322 if(!This
->resource
.heapMemory
) {
1323 This
->resource
.heapMemory
= HeapAlloc(GetProcessHeap() ,0 , This
->resource
.size
+ RESOURCE_ALIGNMENT
);
1325 This
->resource
.allocatedMemory
=
1326 (BYTE
*)(((ULONG_PTR
) This
->resource
.heapMemory
+ (RESOURCE_ALIGNMENT
- 1)) & ~(RESOURCE_ALIGNMENT
- 1));
1327 if(This
->Flags
& SFLAG_INSYSMEM
) {
1328 ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1333 static HRESULT WINAPI
IWineD3DSurfaceImpl_LockRect(IWineD3DSurface
*iface
, WINED3DLOCKED_RECT
* pLockedRect
, CONST RECT
* pRect
, DWORD Flags
) {
1334 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1335 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
1336 const RECT
*pass_rect
= pRect
;
1338 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This
, pRect
, Flags
, pLockedRect
, This
->resource
.allocatedMemory
);
1340 /* This is also done in the base class, but we have to verify this before loading any data from
1341 * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1342 * may interfere, and all other bad things may happen
1344 if (This
->Flags
& SFLAG_LOCKED
) {
1345 WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1346 return WINED3DERR_INVALIDCALL
;
1348 This
->Flags
|= SFLAG_LOCKED
;
1350 if (!(This
->Flags
& SFLAG_LOCKABLE
))
1352 TRACE("Warning: trying to lock unlockable surf@%p\n", This
);
1355 if (Flags
& WINED3DLOCK_DISCARD
) {
1356 /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1357 TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1358 surface_prepare_system_memory(This
); /* Makes sure memory is allocated */
1359 This
->Flags
|= SFLAG_INSYSMEM
;
1363 if (This
->Flags
& SFLAG_INSYSMEM
) {
1364 TRACE("Local copy is up to date, not downloading data\n");
1365 surface_prepare_system_memory(This
); /* Makes sure memory is allocated */
1369 /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1370 * the full surface. Most callers don't need that, so do it here. */
1371 if (pRect
&& pRect
->top
== 0 && pRect
->left
== 0
1372 && pRect
->right
== This
->currentDesc
.Width
1373 && pRect
->bottom
== This
->currentDesc
.Height
)
1378 if (!(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
1379 && ((This
->Flags
& SFLAG_SWAPCHAIN
) || iface
== myDevice
->render_targets
[0])))
1381 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, pass_rect
);
1385 if (This
->Flags
& SFLAG_PBO
)
1387 struct wined3d_context
*context
;
1389 context
= context_acquire(myDevice
, NULL
, CTXUSAGE_RESOURCELOAD
);
1391 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
1392 checkGLcall("glBindBufferARB");
1394 /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1395 if(This
->resource
.allocatedMemory
) {
1396 ERR("The surface already has PBO memory allocated!\n");
1399 This
->resource
.allocatedMemory
= GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, GL_READ_WRITE_ARB
));
1400 checkGLcall("glMapBufferARB");
1402 /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1403 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1404 checkGLcall("glBindBufferARB");
1407 context_release(context
);
1410 if (Flags
& (WINED3DLOCK_NO_DIRTY_UPDATE
| WINED3DLOCK_READONLY
)) {
1413 IWineD3DBaseTexture
*pBaseTexture
;
1416 * as seen in msdn docs
1418 surface_add_dirty_rect(iface
, pRect
);
1420 /** Dirtify Container if needed */
1421 if (SUCCEEDED(IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&pBaseTexture
))) {
1422 TRACE("Making container dirty\n");
1423 IWineD3DBaseTexture_SetDirty(pBaseTexture
, TRUE
);
1424 IWineD3DBaseTexture_Release(pBaseTexture
);
1426 TRACE("Surface is standalone, no need to dirty the container\n");
1430 return IWineD3DBaseSurfaceImpl_LockRect(iface
, pLockedRect
, pRect
, Flags
);
1433 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl
*This
, GLenum fmt
, GLenum type
, UINT bpp
, const BYTE
*mem
) {
1435 GLint prev_rasterpos
[4];
1436 GLint skipBytes
= 0;
1437 UINT pitch
= IWineD3DSurface_GetPitch((IWineD3DSurface
*) This
); /* target is argb, 4 byte */
1438 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
1439 struct wined3d_context
*context
;
1441 /* Activate the correct context for the render target */
1442 context
= context_acquire(myDevice
, (IWineD3DSurface
*) This
, CTXUSAGE_BLIT
);
1445 if (!surface_is_offscreen((IWineD3DSurface
*)This
))
1447 GLenum buffer
= surface_get_gl_buffer((IWineD3DSurface
*)This
);
1448 TRACE("Unlocking %#x buffer.\n", buffer
);
1449 context_set_draw_buffer(context
, buffer
);
1453 /* Primary offscreen render target */
1454 TRACE("Offscreen render target.\n");
1455 context_set_draw_buffer(context
, myDevice
->offscreenBuffer
);
1458 glGetIntegerv(GL_PACK_SWAP_BYTES
, &prev_store
);
1459 checkGLcall("glGetIntegerv");
1460 glGetIntegerv(GL_CURRENT_RASTER_POSITION
, &prev_rasterpos
[0]);
1461 checkGLcall("glGetIntegerv");
1462 glPixelZoom(1.0f
, -1.0f
);
1463 checkGLcall("glPixelZoom");
1465 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1466 glGetIntegerv(GL_UNPACK_ROW_LENGTH
, &skipBytes
);
1467 glPixelStorei(GL_UNPACK_ROW_LENGTH
, This
->currentDesc
.Width
);
1469 glRasterPos3i(This
->lockedRect
.left
, This
->lockedRect
.top
, 1);
1470 checkGLcall("glRasterPos3i");
1472 /* Some drivers(radeon dri, others?) don't like exceptions during
1473 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1474 * after ReleaseDC. Reading it will cause an exception, which x11drv will
1475 * catch to put the dib section in InSync mode, which leads to a crash
1476 * and a blocked x server on my radeon card.
1478 * The following lines read the dib section so it is put in InSync mode
1479 * before glDrawPixels is called and the crash is prevented. There won't
1480 * be any interfering gdi accesses, because UnlockRect is called from
1481 * ReleaseDC, and the app won't use the dc any more afterwards.
1483 if((This
->Flags
& SFLAG_DIBSECTION
) && !(This
->Flags
& SFLAG_PBO
)) {
1485 read
= This
->resource
.allocatedMemory
[0];
1488 if(This
->Flags
& SFLAG_PBO
) {
1489 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
1490 checkGLcall("glBindBufferARB");
1493 /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1494 if(This
->Flags
& SFLAG_LOCKED
) {
1495 glDrawPixels(This
->lockedRect
.right
- This
->lockedRect
.left
,
1496 (This
->lockedRect
.bottom
- This
->lockedRect
.top
)-1,
1498 mem
+ bpp
* This
->lockedRect
.left
+ pitch
* This
->lockedRect
.top
);
1499 checkGLcall("glDrawPixels");
1501 glDrawPixels(This
->currentDesc
.Width
,
1502 This
->currentDesc
.Height
,
1504 checkGLcall("glDrawPixels");
1507 if(This
->Flags
& SFLAG_PBO
) {
1508 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1509 checkGLcall("glBindBufferARB");
1512 glPixelZoom(1.0f
, 1.0f
);
1513 checkGLcall("glPixelZoom");
1515 glRasterPos3iv(&prev_rasterpos
[0]);
1516 checkGLcall("glRasterPos3iv");
1518 /* Reset to previous pack row length */
1519 glPixelStorei(GL_UNPACK_ROW_LENGTH
, skipBytes
);
1520 checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1523 context_release(context
);
1526 static HRESULT WINAPI
IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface
*iface
) {
1527 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1528 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
1531 if (!(This
->Flags
& SFLAG_LOCKED
)) {
1532 WARN("trying to Unlock an unlocked surf@%p\n", This
);
1533 return WINEDDERR_NOTLOCKED
;
1536 if (This
->Flags
& SFLAG_PBO
)
1538 struct wined3d_context
*context
;
1540 TRACE("Freeing PBO memory\n");
1542 context
= context_acquire(myDevice
, NULL
, CTXUSAGE_RESOURCELOAD
);
1544 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, This
->pbo
));
1545 GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
));
1546 GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB
, 0));
1547 checkGLcall("glUnmapBufferARB");
1549 context_release(context
);
1551 This
->resource
.allocatedMemory
= NULL
;
1554 TRACE("(%p) : dirtyfied(%d)\n", This
, This
->Flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
) ? 0 : 1);
1556 if (This
->Flags
& (SFLAG_INDRAWABLE
| SFLAG_INTEXTURE
)) {
1557 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This
);
1561 if ((This
->Flags
& SFLAG_SWAPCHAIN
) || (myDevice
->render_targets
&& iface
== myDevice
->render_targets
[0]))
1563 if(wined3d_settings
.rendertargetlock_mode
== RTL_DISABLE
) {
1564 static BOOL warned
= FALSE
;
1566 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1572 if(This
->dirtyRect
.left
== 0 &&
1573 This
->dirtyRect
.top
== 0 &&
1574 This
->dirtyRect
.right
== This
->currentDesc
.Width
&&
1575 This
->dirtyRect
.bottom
== This
->currentDesc
.Height
) {
1578 /* TODO: Proper partial rectangle tracking */
1579 fullsurface
= FALSE
;
1580 This
->Flags
|= SFLAG_INSYSMEM
;
1583 switch(wined3d_settings
.rendertargetlock_mode
) {
1585 IWineD3DSurface_LoadLocation(iface
, SFLAG_INTEXTURE
, NULL
/* partial texture loading not supported yet */);
1589 IWineD3DSurface_LoadLocation(iface
, SFLAG_INDRAWABLE
, fullsurface
? NULL
: &This
->dirtyRect
);
1594 /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1595 * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1596 * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1597 * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1598 * not fully up to date because only a subrectangle was read in LockRect.
1600 This
->Flags
&= ~SFLAG_INSYSMEM
;
1601 This
->Flags
|= SFLAG_INDRAWABLE
;
1604 This
->dirtyRect
.left
= This
->currentDesc
.Width
;
1605 This
->dirtyRect
.top
= This
->currentDesc
.Height
;
1606 This
->dirtyRect
.right
= 0;
1607 This
->dirtyRect
.bottom
= 0;
1608 } else if(iface
== myDevice
->stencilBufferTarget
) {
1609 FIXME("Depth Stencil buffer locking is not implemented\n");
1611 /* The rest should be a normal texture */
1612 IWineD3DBaseTextureImpl
*impl
;
1613 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1614 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1615 * states need resetting
1617 if(IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&impl
) == WINED3D_OK
) {
1618 if(impl
->baseTexture
.bindCount
) {
1619 IWineD3DDeviceImpl_MarkStateDirty(myDevice
, STATE_SAMPLER(impl
->baseTexture
.sampler
));
1621 IWineD3DBaseTexture_Release((IWineD3DBaseTexture
*) impl
);
1626 This
->Flags
&= ~SFLAG_LOCKED
;
1627 memset(&This
->lockedRect
, 0, sizeof(RECT
));
1629 /* Overlays have to be redrawn manually after changes with the GL implementation */
1630 if(This
->overlay_dest
) {
1631 IWineD3DSurface_DrawOverlay(iface
);
1636 static void surface_release_client_storage(IWineD3DSurface
*iface
)
1638 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
1639 struct wined3d_context
*context
;
1641 context
= context_acquire(This
->resource
.device
, NULL
, CTXUSAGE_RESOURCELOAD
);
1644 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_FALSE
);
1645 if(This
->texture_name
)
1647 surface_bind_and_dirtify(This
, FALSE
);
1648 glTexImage2D(This
->texture_target
, This
->texture_level
,
1649 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1651 if(This
->texture_name_srgb
)
1653 surface_bind_and_dirtify(This
, TRUE
);
1654 glTexImage2D(This
->texture_target
, This
->texture_level
,
1655 GL_RGB
, 1, 1, 0, GL_RGB
, GL_UNSIGNED_BYTE
, NULL
);
1657 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE
, GL_TRUE
);
1660 context_release(context
);
1662 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSRGBTEX
, FALSE
);
1663 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INTEXTURE
, FALSE
);
1664 surface_force_reload(iface
);
1667 static HRESULT WINAPI
IWineD3DSurfaceImpl_GetDC(IWineD3DSurface
*iface
, HDC
*pHDC
)
1669 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1670 WINED3DLOCKED_RECT lock
;
1674 TRACE("(%p)->(%p)\n",This
,pHDC
);
1676 if(This
->Flags
& SFLAG_USERPTR
) {
1677 ERR("Not supported on surfaces with an application-provided surfaces\n");
1678 return WINEDDERR_NODC
;
1681 /* Give more detailed info for ddraw */
1682 if (This
->Flags
& SFLAG_DCINUSE
)
1683 return WINEDDERR_DCALREADYCREATED
;
1685 /* Can't GetDC if the surface is locked */
1686 if (This
->Flags
& SFLAG_LOCKED
)
1687 return WINED3DERR_INVALIDCALL
;
1689 memset(&lock
, 0, sizeof(lock
)); /* To be sure */
1691 /* Create a DIB section if there isn't a hdc yet */
1693 if(This
->Flags
& SFLAG_CLIENT
) {
1694 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
);
1695 surface_release_client_storage(iface
);
1697 hr
= IWineD3DBaseSurfaceImpl_CreateDIBSection(iface
);
1698 if(FAILED(hr
)) return WINED3DERR_INVALIDCALL
;
1700 /* Use the dib section from now on if we are not using a PBO */
1701 if(!(This
->Flags
& SFLAG_PBO
))
1702 This
->resource
.allocatedMemory
= This
->dib
.bitmap_data
;
1705 /* Lock the surface */
1706 hr
= IWineD3DSurface_LockRect(iface
,
1711 if(This
->Flags
& SFLAG_PBO
) {
1712 /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
1713 memcpy(This
->dib
.bitmap_data
, This
->resource
.allocatedMemory
, This
->dib
.bitmap_size
);
1717 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr
);
1718 /* keep the dib section */
1722 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
1723 || This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
)
1725 /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
1726 D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
1728 const PALETTEENTRY
*pal
= NULL
;
1731 pal
= This
->palette
->palents
;
1733 IWineD3DSurfaceImpl
*dds_primary
;
1734 IWineD3DSwapChainImpl
*swapchain
;
1735 swapchain
= (IWineD3DSwapChainImpl
*)This
->resource
.device
->swapchains
[0];
1736 dds_primary
= (IWineD3DSurfaceImpl
*)swapchain
->frontBuffer
;
1737 if (dds_primary
&& dds_primary
->palette
)
1738 pal
= dds_primary
->palette
->palents
;
1742 for (n
=0; n
<256; n
++) {
1743 col
[n
].rgbRed
= pal
[n
].peRed
;
1744 col
[n
].rgbGreen
= pal
[n
].peGreen
;
1745 col
[n
].rgbBlue
= pal
[n
].peBlue
;
1746 col
[n
].rgbReserved
= 0;
1748 SetDIBColorTable(This
->hDC
, 0, 256, col
);
1753 TRACE("returning %p\n",*pHDC
);
1754 This
->Flags
|= SFLAG_DCINUSE
;
1759 static HRESULT WINAPI
IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface
*iface
, HDC hDC
)
1761 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
1763 TRACE("(%p)->(%p)\n",This
,hDC
);
1765 if (!(This
->Flags
& SFLAG_DCINUSE
))
1766 return WINEDDERR_NODC
;
1768 if (This
->hDC
!=hDC
) {
1769 WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC
, This
->hDC
);
1770 return WINEDDERR_NODC
;
1773 if((This
->Flags
& SFLAG_PBO
) && This
->resource
.allocatedMemory
) {
1774 /* Copy the contents of the DIB over to the PBO */
1775 memcpy(This
->resource
.allocatedMemory
, This
->dib
.bitmap_data
, This
->dib
.bitmap_size
);
1778 /* we locked first, so unlock now */
1779 IWineD3DSurface_UnlockRect(iface
);
1781 This
->Flags
&= ~SFLAG_DCINUSE
;
1786 /* ******************************************************
1787 IWineD3DSurface Internal (No mapping to directx api) parts follow
1788 ****************************************************** */
1790 HRESULT
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
) {
1791 BOOL colorkey_active
= need_alpha_ck
&& (This
->CKeyFlags
& WINEDDSD_CKSRCBLT
);
1792 const struct GlPixelFormatDesc
*glDesc
= This
->resource
.format_desc
;
1793 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
1794 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
1796 /* Default values: From the surface */
1797 *format
= glDesc
->glFormat
;
1798 *type
= glDesc
->glType
;
1799 *convert
= NO_CONVERSION
;
1800 *target_bpp
= glDesc
->byte_count
;
1803 *internal
= glDesc
->glGammaInternal
;
1805 else if (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
1806 && surface_is_offscreen((IWineD3DSurface
*) This
))
1808 *internal
= glDesc
->rtInternal
;
1810 *internal
= glDesc
->glInternal
;
1813 /* Ok, now look if we have to do any conversion */
1814 switch(This
->resource
.format_desc
->format
)
1816 case WINED3DFMT_P8_UINT
:
1821 /* Use conversion when the paletted texture extension OR fragment shaders are available. When either
1822 * of the two is available make sure texturing is requested as neither of the two works in
1823 * conjunction with calls like glDraw-/glReadPixels. Further also use conversion in case of color keying.
1824 * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
1825 * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
1826 * conflicts with this.
1828 if (!(gl_info
->supported
[EXT_PALETTED_TEXTURE
] || (gl_info
->supported
[ARB_FRAGMENT_PROGRAM
]
1829 && device
->render_targets
&& This
== (IWineD3DSurfaceImpl
*)device
->render_targets
[0]))
1830 || colorkey_active
|| !use_texturing
)
1833 *internal
= GL_RGBA
;
1834 *type
= GL_UNSIGNED_BYTE
;
1836 if(colorkey_active
) {
1837 *convert
= CONVERT_PALETTED_CK
;
1839 *convert
= CONVERT_PALETTED
;
1842 else if (!gl_info
->supported
[EXT_PALETTED_TEXTURE
] && gl_info
->supported
[ARB_FRAGMENT_PROGRAM
])
1845 *type
= GL_UNSIGNED_BYTE
;
1851 case WINED3DFMT_B2G3R3_UNORM
:
1852 /* **********************
1853 GL_UNSIGNED_BYTE_3_3_2
1854 ********************** */
1855 if (colorkey_active
) {
1856 /* This texture format will never be used.. So do not care about color keying
1857 up until the point in time it will be needed :-) */
1858 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1862 case WINED3DFMT_B5G6R5_UNORM
:
1863 if (colorkey_active
) {
1864 *convert
= CONVERT_CK_565
;
1866 *internal
= GL_RGB5_A1
;
1867 *type
= GL_UNSIGNED_SHORT_5_5_5_1
;
1871 case WINED3DFMT_B5G5R5X1_UNORM
:
1872 if (colorkey_active
) {
1873 *convert
= CONVERT_CK_5551
;
1875 *internal
= GL_RGB5_A1
;
1876 *type
= GL_UNSIGNED_SHORT_1_5_5_5_REV
;
1880 case WINED3DFMT_B8G8R8_UNORM
:
1881 if (colorkey_active
) {
1882 *convert
= CONVERT_CK_RGB24
;
1884 *internal
= GL_RGBA8
;
1885 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1890 case WINED3DFMT_B8G8R8X8_UNORM
:
1891 if (colorkey_active
) {
1892 *convert
= CONVERT_RGB32_888
;
1894 *internal
= GL_RGBA8
;
1895 *type
= GL_UNSIGNED_INT_8_8_8_8
;
1899 case WINED3DFMT_R8G8_SNORM
:
1900 if (gl_info
->supported
[NV_TEXTURE_SHADER
]) break;
1901 *convert
= CONVERT_V8U8
;
1903 *type
= GL_UNSIGNED_BYTE
;
1907 case WINED3DFMT_R5G5_SNORM_L6_UNORM
:
1908 *convert
= CONVERT_L6V5U5
;
1909 if (gl_info
->supported
[NV_TEXTURE_SHADER
])
1912 /* Use format and types from table */
1914 /* Load it into unsigned R5G6B5, swap L and V channels, and revert that in the shader */
1917 *type
= GL_UNSIGNED_SHORT_5_6_5
;
1921 case WINED3DFMT_R8G8_SNORM_L8X8_UNORM
:
1922 *convert
= CONVERT_X8L8V8U8
;
1924 if (gl_info
->supported
[NV_TEXTURE_SHADER
])
1926 /* Use formats from gl table. It is a bit unfortunate, but the conversion
1927 * is needed to set the X format to 255 to get 1.0 for alpha when sampling
1928 * the texture. OpenGL can't use GL_DSDT8_MAG8_NV as internal format with
1929 * the needed type and format parameter, so the internal format contains a
1930 * 4th component, which is returned as alpha
1934 *type
= GL_UNSIGNED_INT_8_8_8_8_REV
;
1938 case WINED3DFMT_R8G8B8A8_SNORM
:
1939 if (gl_info
->supported
[NV_TEXTURE_SHADER
]) break;
1940 *convert
= CONVERT_Q8W8V8U8
;
1942 *type
= GL_UNSIGNED_BYTE
;
1946 case WINED3DFMT_R16G16_SNORM
:
1947 if (gl_info
->supported
[NV_TEXTURE_SHADER
]) break;
1948 *convert
= CONVERT_V16U16
;
1950 *type
= GL_UNSIGNED_SHORT
;
1954 case WINED3DFMT_L4A4_UNORM
:
1955 /* WINED3DFMT_L4A4_UNORM exists as an internal gl format, but for some reason there is not
1956 * format+type combination to load it. Thus convert it to A8L8, then load it
1957 * with A4L4 internal, but A8L8 format+type
1959 *convert
= CONVERT_A4L4
;
1960 *format
= GL_LUMINANCE_ALPHA
;
1961 *type
= GL_UNSIGNED_BYTE
;
1965 case WINED3DFMT_R16G16_UNORM
:
1966 *convert
= CONVERT_G16R16
;
1968 *type
= GL_UNSIGNED_SHORT
;
1972 case WINED3DFMT_R16G16_FLOAT
:
1973 *convert
= CONVERT_R16G16F
;
1975 *type
= GL_HALF_FLOAT_ARB
;
1979 case WINED3DFMT_R32G32_FLOAT
:
1980 *convert
= CONVERT_R32G32F
;
1986 case WINED3DFMT_S1_UINT_D15_UNORM
:
1987 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1988 || gl_info
->supported
[EXT_PACKED_DEPTH_STENCIL
])
1990 *convert
= CONVERT_D15S1
;
1995 case WINED3DFMT_S4X4_UINT_D24_UNORM
:
1996 if (gl_info
->supported
[ARB_FRAMEBUFFER_OBJECT
]
1997 || gl_info
->supported
[EXT_PACKED_DEPTH_STENCIL
])
1999 *convert
= CONVERT_D24X4S4
;
2003 case WINED3DFMT_S8_UINT_D24_FLOAT
:
2004 if (gl_info
->supported
[ARB_DEPTH_BUFFER_FLOAT
])
2006 *convert
= CONVERT_D24FS8
;
2018 static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl
*This
, BYTE table
[256][4], BOOL colorkey
)
2020 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
2021 IWineD3DPaletteImpl
*pal
= This
->palette
;
2022 BOOL index_in_alpha
= FALSE
;
2025 /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2026 * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2027 * is slow. Further RGB->P8 conversion is not possible because palettes can have
2028 * duplicate entries. Store the color key in the unused alpha component to speed the
2029 * download up and to make conversion unneeded. */
2030 index_in_alpha
= primary_render_target_is_p8(device
);
2034 UINT dxVersion
= ((IWineD3DImpl
*)device
->wined3d
)->dxVersion
;
2036 /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2039 ERR("This code should never get entered for DirectDraw!, expect problems\n");
2042 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2043 * there's no palette at this time. */
2044 for (i
= 0; i
< 256; i
++) table
[i
][3] = i
;
2049 /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2050 * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2051 * capability flag is present (wine does advertise this capability) */
2052 for (i
= 0; i
< 256; ++i
)
2054 table
[i
][0] = device
->palettes
[device
->currentPalette
][i
].peRed
;
2055 table
[i
][1] = device
->palettes
[device
->currentPalette
][i
].peGreen
;
2056 table
[i
][2] = device
->palettes
[device
->currentPalette
][i
].peBlue
;
2057 table
[i
][3] = device
->palettes
[device
->currentPalette
][i
].peFlags
;
2063 TRACE("Using surface palette %p\n", pal
);
2064 /* Get the surface's palette */
2065 for (i
= 0; i
< 256; ++i
)
2067 table
[i
][0] = pal
->palents
[i
].peRed
;
2068 table
[i
][1] = pal
->palents
[i
].peGreen
;
2069 table
[i
][2] = pal
->palents
[i
].peBlue
;
2071 /* When index_in_alpha is set the palette index is stored in the
2072 * alpha component. In case of a readback we can then read
2073 * GL_ALPHA. Color keying is handled in BltOverride using a
2074 * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2075 * color key itself is passed to glAlphaFunc in other cases the
2076 * alpha component of pixels that should be masked away is set to 0. */
2081 else if (colorkey
&& (i
>= This
->SrcBltCKey
.dwColorSpaceLowValue
)
2082 && (i
<= This
->SrcBltCKey
.dwColorSpaceHighValue
))
2086 else if(pal
->Flags
& WINEDDPCAPS_ALPHA
)
2088 table
[i
][3] = pal
->palents
[i
].peFlags
;
2098 static HRESULT
d3dfmt_convert_surface(const BYTE
*src
, BYTE
*dst
, UINT pitch
, UINT width
,
2099 UINT height
, UINT outpitch
, CONVERT_TYPES convert
, IWineD3DSurfaceImpl
*This
)
2101 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
2102 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2105 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src
, dst
, pitch
, height
, outpitch
, convert
,This
);
2110 memcpy(dst
, src
, pitch
* height
);
2113 case CONVERT_PALETTED
:
2114 case CONVERT_PALETTED_CK
:
2116 IWineD3DPaletteImpl
* pal
= This
->palette
;
2121 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2124 d3dfmt_p8_init_palette(This
, table
, (convert
== CONVERT_PALETTED_CK
));
2126 for (y
= 0; y
< height
; y
++)
2128 source
= src
+ pitch
* y
;
2129 dest
= dst
+ outpitch
* y
;
2130 /* This is an 1 bpp format, using the width here is fine */
2131 for (x
= 0; x
< width
; x
++) {
2132 BYTE color
= *source
++;
2133 *dest
++ = table
[color
][0];
2134 *dest
++ = table
[color
][1];
2135 *dest
++ = table
[color
][2];
2136 *dest
++ = table
[color
][3];
2142 case CONVERT_CK_565
:
2144 /* Converting the 565 format in 5551 packed to emulate color-keying.
2146 Note : in all these conversion, it would be best to average the averaging
2147 pixels to get the color of the pixel that will be color-keyed to
2148 prevent 'color bleeding'. This will be done later on if ever it is
2151 Note2: Nvidia documents say that their driver does not support alpha + color keying
2152 on the same surface and disables color keying in such a case
2158 TRACE("Color keyed 565\n");
2160 for (y
= 0; y
< height
; y
++) {
2161 Source
= (const WORD
*)(src
+ y
* pitch
);
2162 Dest
= (WORD
*) (dst
+ y
* outpitch
);
2163 for (x
= 0; x
< width
; x
++ ) {
2164 WORD color
= *Source
++;
2165 *Dest
= ((color
& 0xFFC0) | ((color
& 0x1F) << 1));
2166 if ((color
< This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
2167 (color
> This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
2176 case CONVERT_CK_5551
:
2178 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2182 TRACE("Color keyed 5551\n");
2183 for (y
= 0; y
< height
; y
++) {
2184 Source
= (const WORD
*)(src
+ y
* pitch
);
2185 Dest
= (WORD
*) (dst
+ y
* outpitch
);
2186 for (x
= 0; x
< width
; x
++ ) {
2187 WORD color
= *Source
++;
2189 if ((color
< This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
2190 (color
> This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
2194 *Dest
&= ~(1 << 15);
2202 case CONVERT_CK_RGB24
:
2204 /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2206 for (y
= 0; y
< height
; y
++)
2208 source
= src
+ pitch
* y
;
2209 dest
= dst
+ outpitch
* y
;
2210 for (x
= 0; x
< width
; x
++) {
2211 DWORD color
= ((DWORD
)source
[0] << 16) + ((DWORD
)source
[1] << 8) + (DWORD
)source
[2] ;
2212 DWORD dstcolor
= color
<< 8;
2213 if ((color
< This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
2214 (color
> This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
2217 *(DWORD
*)dest
= dstcolor
;
2225 case CONVERT_RGB32_888
:
2227 /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2229 for (y
= 0; y
< height
; y
++)
2231 source
= src
+ pitch
* y
;
2232 dest
= dst
+ outpitch
* y
;
2233 for (x
= 0; x
< width
; x
++) {
2234 DWORD color
= 0xffffff & *(const DWORD
*)source
;
2235 DWORD dstcolor
= color
<< 8;
2236 if ((color
< This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
2237 (color
> This
->SrcBltCKey
.dwColorSpaceHighValue
)) {
2240 *(DWORD
*)dest
= dstcolor
;
2251 const short *Source
;
2252 unsigned char *Dest
;
2253 for(y
= 0; y
< height
; y
++) {
2254 Source
= (const short *)(src
+ y
* pitch
);
2255 Dest
= dst
+ y
* outpitch
;
2256 for (x
= 0; x
< width
; x
++ ) {
2257 long color
= (*Source
++);
2258 /* B */ Dest
[0] = 0xff;
2259 /* G */ Dest
[1] = (color
>> 8) + 128; /* V */
2260 /* R */ Dest
[2] = (color
) + 128; /* U */
2267 case CONVERT_V16U16
:
2270 const DWORD
*Source
;
2271 unsigned short *Dest
;
2272 for(y
= 0; y
< height
; y
++) {
2273 Source
= (const DWORD
*)(src
+ y
* pitch
);
2274 Dest
= (unsigned short *) (dst
+ y
* outpitch
);
2275 for (x
= 0; x
< width
; x
++ ) {
2276 DWORD color
= (*Source
++);
2277 /* B */ Dest
[0] = 0xffff;
2278 /* G */ Dest
[1] = (color
>> 16) + 32768; /* V */
2279 /* R */ Dest
[2] = (color
) + 32768; /* U */
2286 case CONVERT_Q8W8V8U8
:
2289 const DWORD
*Source
;
2290 unsigned char *Dest
;
2291 for(y
= 0; y
< height
; y
++) {
2292 Source
= (const DWORD
*)(src
+ y
* pitch
);
2293 Dest
= dst
+ y
* outpitch
;
2294 for (x
= 0; x
< width
; x
++ ) {
2295 long color
= (*Source
++);
2296 /* B */ Dest
[0] = ((color
>> 16) & 0xff) + 128; /* W */
2297 /* G */ Dest
[1] = ((color
>> 8 ) & 0xff) + 128; /* V */
2298 /* R */ Dest
[2] = (color
& 0xff) + 128; /* U */
2299 /* A */ Dest
[3] = ((color
>> 24) & 0xff) + 128; /* Q */
2306 case CONVERT_L6V5U5
:
2310 unsigned char *Dest
;
2312 if (gl_info
->supported
[NV_TEXTURE_SHADER
])
2314 /* This makes the gl surface bigger(24 bit instead of 16), but it works with
2315 * fixed function and shaders without further conversion once the surface is
2318 for(y
= 0; y
< height
; y
++) {
2319 Source
= (const WORD
*)(src
+ y
* pitch
);
2320 Dest
= dst
+ y
* outpitch
;
2321 for (x
= 0; x
< width
; x
++ ) {
2322 short color
= (*Source
++);
2323 unsigned char l
= ((color
>> 10) & 0xfc);
2324 char v
= ((color
>> 5) & 0x3e);
2325 char u
= ((color
) & 0x1f);
2327 /* 8 bits destination, 6 bits source, 8th bit is the sign. gl ignores the sign
2328 * and doubles the positive range. Thus shift left only once, gl does the 2nd
2329 * shift. GL reads a signed value and converts it into an unsigned value.
2331 /* M */ Dest
[2] = l
<< 1;
2333 /* Those are read as signed, but kept signed. Just left-shift 3 times to scale
2334 * from 5 bit values to 8 bit values.
2336 /* V */ Dest
[1] = v
<< 3;
2337 /* U */ Dest
[0] = u
<< 3;
2342 for(y
= 0; y
< height
; y
++) {
2343 unsigned short *Dest_s
= (unsigned short *) (dst
+ y
* outpitch
);
2344 Source
= (const WORD
*)(src
+ y
* pitch
);
2345 for (x
= 0; x
< width
; x
++ ) {
2346 short color
= (*Source
++);
2347 unsigned char l
= ((color
>> 10) & 0xfc);
2348 short v
= ((color
>> 5) & 0x3e);
2349 short u
= ((color
) & 0x1f);
2350 short v_conv
= v
+ 16;
2351 short u_conv
= u
+ 16;
2353 *Dest_s
= ((v_conv
<< 11) & 0xf800) | ((l
<< 5) & 0x7e0) | (u_conv
& 0x1f);
2361 case CONVERT_X8L8V8U8
:
2364 const DWORD
*Source
;
2365 unsigned char *Dest
;
2367 if (gl_info
->supported
[NV_TEXTURE_SHADER
])
2369 /* This implementation works with the fixed function pipeline and shaders
2370 * without further modification after converting the surface.
2372 for(y
= 0; y
< height
; y
++) {
2373 Source
= (const DWORD
*)(src
+ y
* pitch
);
2374 Dest
= dst
+ y
* outpitch
;
2375 for (x
= 0; x
< width
; x
++ ) {
2376 long color
= (*Source
++);
2377 /* L */ Dest
[2] = ((color
>> 16) & 0xff); /* L */
2378 /* V */ Dest
[1] = ((color
>> 8 ) & 0xff); /* V */
2379 /* U */ Dest
[0] = (color
& 0xff); /* U */
2380 /* I */ Dest
[3] = 255; /* X */
2385 /* Doesn't work correctly with the fixed function pipeline, but can work in
2386 * shaders if the shader is adjusted. (There's no use for this format in gl's
2387 * standard fixed function pipeline anyway).
2389 for(y
= 0; y
< height
; y
++) {
2390 Source
= (const DWORD
*)(src
+ y
* pitch
);
2391 Dest
= dst
+ y
* outpitch
;
2392 for (x
= 0; x
< width
; x
++ ) {
2393 long color
= (*Source
++);
2394 /* B */ Dest
[0] = ((color
>> 16) & 0xff); /* L */
2395 /* G */ Dest
[1] = ((color
>> 8 ) & 0xff) + 128; /* V */
2396 /* R */ Dest
[2] = (color
& 0xff) + 128; /* U */
2407 const unsigned char *Source
;
2408 unsigned char *Dest
;
2409 for(y
= 0; y
< height
; y
++) {
2410 Source
= src
+ y
* pitch
;
2411 Dest
= dst
+ y
* outpitch
;
2412 for (x
= 0; x
< width
; x
++ ) {
2413 unsigned char color
= (*Source
++);
2414 /* A */ Dest
[1] = (color
& 0xf0) << 0;
2415 /* L */ Dest
[0] = (color
& 0x0f) << 4;
2422 case CONVERT_G16R16
:
2423 case CONVERT_R16G16F
:
2429 for(y
= 0; y
< height
; y
++) {
2430 Source
= (const WORD
*)(src
+ y
* pitch
);
2431 Dest
= (WORD
*) (dst
+ y
* outpitch
);
2432 for (x
= 0; x
< width
; x
++ ) {
2433 WORD green
= (*Source
++);
2434 WORD red
= (*Source
++);
2437 /* Strictly speaking not correct for R16G16F, but it doesn't matter because the
2438 * shader overwrites it anyway
2447 case CONVERT_R32G32F
:
2450 const float *Source
;
2452 for(y
= 0; y
< height
; y
++) {
2453 Source
= (const float *)(src
+ y
* pitch
);
2454 Dest
= (float *) (dst
+ y
* outpitch
);
2455 for (x
= 0; x
< width
; x
++ ) {
2456 float green
= (*Source
++);
2457 float red
= (*Source
++);
2471 for (y
= 0; y
< height
; ++y
)
2473 const WORD
*source
= (const WORD
*)(src
+ y
* pitch
);
2474 DWORD
*dest
= (DWORD
*)(dst
+ y
* outpitch
);
2476 for (x
= 0; x
< width
; ++x
)
2478 /* The depth data is normalized, so needs to be scaled,
2479 * the stencil data isn't. Scale depth data by
2480 * (2^24-1)/(2^15-1) ~~ (2^9 + 2^-6). */
2481 WORD d15
= source
[x
] >> 1;
2482 DWORD d24
= (d15
<< 9) + (d15
>> 6);
2483 dest
[x
] = (d24
<< 8) | (source
[x
] & 0x1);
2489 case CONVERT_D24X4S4
:
2493 for (y
= 0; y
< height
; ++y
)
2495 const DWORD
*source
= (const DWORD
*)(src
+ y
* pitch
);
2496 DWORD
*dest
= (DWORD
*)(dst
+ y
* outpitch
);
2498 for (x
= 0; x
< width
; ++x
)
2500 /* Just need to clear out the X4 part. */
2501 dest
[x
] = source
[x
] & ~0xf0;
2507 case CONVERT_D24FS8
:
2511 for (y
= 0; y
< height
; ++y
)
2513 const DWORD
*source
= (const DWORD
*)(src
+ y
* pitch
);
2514 float *dest_f
= (float *)(dst
+ y
* outpitch
);
2515 DWORD
*dest_s
= (DWORD
*)(dst
+ y
* outpitch
);
2517 for (x
= 0; x
< width
; ++x
)
2519 dest_f
[x
* 2] = float_24_to_32((source
[x
] & 0xffffff00) >> 8);
2520 dest_s
[x
* 2 + 1] = source
[x
] & 0xff;
2527 ERR("Unsupported conversion type %#x.\n", convert
);
2532 /* This function is used in case of 8bit paletted textures to upload the palette.
2533 It supports GL_EXT_paletted_texture and GL_ARB_fragment_program, support for other
2534 extensions like ATI_fragment_shaders is possible.
2536 /* Context activation is done by the caller. */
2537 static void d3dfmt_p8_upload_palette(IWineD3DSurface
*iface
, CONVERT_TYPES convert
) {
2538 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2540 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
2541 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
2543 d3dfmt_p8_init_palette(This
, table
, (convert
== CONVERT_PALETTED_CK
));
2545 /* Try to use the paletted texture extension */
2546 if (gl_info
->supported
[EXT_PALETTED_TEXTURE
])
2548 TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
2550 GL_EXTCALL(glColorTableEXT(This
->texture_target
, GL_RGBA
, 256, GL_RGBA
, GL_UNSIGNED_BYTE
, table
));
2555 /* Let a fragment shader do the color conversion by uploading the palette to a 1D texture.
2556 * The 8bit pixel data will be used as an index in this palette texture to retrieve the final color. */
2557 TRACE("Using fragment shaders for emulating 8-bit paletted texture support\n");
2561 /* Create the fragment program if we don't have it */
2562 if(!device
->paletteConversionShader
)
2564 const char *fragment_palette_conversion
=
2567 /* { 255/256, 0.5/255*255/256, 0, 0 } */
2568 "PARAM constants = { 0.996, 0.00195, 0, 0 };\n"
2569 /* The alpha-component contains the palette index */
2570 "TEX index, fragment.texcoord[0], texture[0], 2D;\n"
2571 /* Scale the index by 255/256 and add a bias of '0.5' in order to sample in the middle */
2572 "MAD index.a, index.a, constants.x, constants.y;\n"
2573 /* Use the alpha-component as an index in the palette to get the final color */
2574 "TEX result.color, index.a, texture[1], 1D;\n"
2577 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
2578 GL_EXTCALL(glGenProgramsARB(1, &device
->paletteConversionShader
));
2579 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, device
->paletteConversionShader
));
2580 GL_EXTCALL(glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB
, GL_PROGRAM_FORMAT_ASCII_ARB
, strlen(fragment_palette_conversion
), fragment_palette_conversion
));
2581 glDisable(GL_FRAGMENT_PROGRAM_ARB
);
2584 glEnable(GL_FRAGMENT_PROGRAM_ARB
);
2585 GL_EXTCALL(glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB
, device
->paletteConversionShader
));
2587 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1
));
2588 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
2590 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2591 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
); /* Make sure we have discrete color levels. */
2592 glTexParameteri(GL_TEXTURE_1D
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2593 glTexImage1D(GL_TEXTURE_1D
, 0, GL_RGBA
, 256, 0, GL_RGBA
, GL_UNSIGNED_BYTE
, table
); /* Upload the palette */
2595 /* Switch back to unit 0 in which the 2D texture will be stored. */
2596 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0
));
2598 /* Rebind the texture because it isn't bound anymore */
2599 glBindTexture(This
->texture_target
, This
->texture_name
);
2605 BOOL
palette9_changed(IWineD3DSurfaceImpl
*This
)
2607 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
2609 if (This
->palette
|| (This
->resource
.format_desc
->format
!= WINED3DFMT_P8_UINT
2610 && This
->resource
.format_desc
->format
!= WINED3DFMT_P8_UINT_A8_UNORM
))
2612 /* If a ddraw-style palette is attached assume no d3d9 palette change.
2613 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2620 if (!memcmp(This
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256))
2625 This
->palette9
= HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY
) * 256);
2627 memcpy(This
->palette9
, device
->palettes
[device
->currentPalette
], sizeof(PALETTEENTRY
) * 256);
2631 static HRESULT WINAPI
IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface
*iface
, BOOL srgb_mode
) {
2632 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2633 DWORD flag
= srgb_mode
? SFLAG_INSRGBTEX
: SFLAG_INTEXTURE
;
2635 if (!(This
->Flags
& flag
)) {
2636 TRACE("Reloading because surface is dirty\n");
2637 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2638 ((This
->Flags
& SFLAG_GLCKEY
) && (!(This
->CKeyFlags
& WINEDDSD_CKSRCBLT
))) ||
2639 /* Reload: vice versa OR */
2640 ((!(This
->Flags
& SFLAG_GLCKEY
)) && (This
->CKeyFlags
& WINEDDSD_CKSRCBLT
)) ||
2641 /* Also reload: Color key is active AND the color key has changed */
2642 ((This
->CKeyFlags
& WINEDDSD_CKSRCBLT
) && (
2643 (This
->glCKey
.dwColorSpaceLowValue
!= This
->SrcBltCKey
.dwColorSpaceLowValue
) ||
2644 (This
->glCKey
.dwColorSpaceHighValue
!= This
->SrcBltCKey
.dwColorSpaceHighValue
)))) {
2645 TRACE("Reloading because of color keying\n");
2646 /* To perform the color key conversion we need a sysmem copy of
2647 * the surface. Make sure we have it
2650 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
);
2651 /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2652 /* TODO: This is not necessarily needed with hw palettized texture support */
2653 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, TRUE
);
2655 TRACE("surface is already in texture\n");
2659 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2660 * These resources are not bound by device size or format restrictions. Because of this,
2661 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2662 * However, these resources can always be created, locked, and copied.
2664 if (This
->resource
.pool
== WINED3DPOOL_SCRATCH
)
2666 FIXME("(%p) Operation not supported for scratch textures\n",This
);
2667 return WINED3DERR_INVALIDCALL
;
2670 IWineD3DSurface_LoadLocation(iface
, flag
, NULL
/* no partial locking for textures yet */);
2674 static unsigned int gen
= 0;
2677 if ((gen
% 10) == 0) {
2678 snprintf(buffer
, sizeof(buffer
), "/tmp/surface%p_type%u_level%u_%u.ppm",
2679 This
, This
->texture_target
, This
->texture_level
, gen
);
2680 IWineD3DSurfaceImpl_SaveSnapshot(iface
, buffer
);
2683 * debugging crash code
2692 if (!(This
->Flags
& SFLAG_DONOTFREE
)) {
2693 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
2694 This
->resource
.allocatedMemory
= NULL
;
2695 This
->resource
.heapMemory
= NULL
;
2696 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, FALSE
);
2702 /* Context activation is done by the caller. */
2703 static void WINAPI
IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface
*iface
, BOOL srgb
) {
2704 /* TODO: check for locks */
2705 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2706 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
2707 IWineD3DBaseTexture
*baseTexture
= NULL
;
2709 TRACE("(%p)Checking to see if the container is a base texture\n", This
);
2710 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&baseTexture
) == WINED3D_OK
) {
2711 TRACE("Passing to container\n");
2712 IWineD3DBaseTexture_BindTexture(baseTexture
, srgb
);
2713 IWineD3DBaseTexture_Release(baseTexture
);
2717 struct wined3d_context
*context
= NULL
;
2720 TRACE("(%p) : Binding surface\n", This
);
2722 name
= srgb
? &This
->texture_name_srgb
: &This
->texture_name
;
2723 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
2727 if (!This
->texture_level
)
2730 glGenTextures(1, name
);
2731 checkGLcall("glGenTextures");
2732 TRACE("Surface %p given name %d\n", This
, *name
);
2734 glBindTexture(This
->texture_target
, *name
);
2735 checkGLcall("glBindTexture");
2736 glTexParameteri(This
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
2737 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2738 glTexParameteri(This
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
2739 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2740 glTexParameteri(This
->texture_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
2741 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2742 glTexParameteri(This
->texture_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
2743 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2744 glTexParameteri(This
->texture_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
2745 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2747 /* This is where we should be reducing the amount of GLMemoryUsed */
2749 /* Mipmap surfaces should have a base texture container */
2750 ERR("Mipmap surface has a glTexture bound to it!\n");
2753 glBindTexture(This
->texture_target
, *name
);
2754 checkGLcall("glBindTexture");
2758 if (context
) context_release(context
);
2765 static HRESULT WINAPI
IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface
*iface
, const char* filename
)
2768 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2769 char *allocatedMemory
;
2770 const char *textureRow
;
2771 IWineD3DSwapChain
*swapChain
= NULL
;
2772 int width
, height
, i
, y
;
2773 GLuint tmpTexture
= 0;
2776 Textures may not be stored in ->allocatedgMemory and a GlTexture
2777 so we should lock the surface before saving a snapshot, or at least check that
2779 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2780 by calling GetTexImage and in compressed form by calling
2781 GetCompressedTexImageARB. Queried compressed images can be saved and
2782 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2783 texture images do not need to be processed by the GL and should
2784 significantly improve texture loading performance relative to uncompressed
2787 /* Setup the width and height to be the internal texture width and height. */
2788 width
= This
->pow2Width
;
2789 height
= This
->pow2Height
;
2790 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2791 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **)&swapChain
);
2793 if (This
->Flags
& SFLAG_INDRAWABLE
&& !(This
->Flags
& SFLAG_INTEXTURE
)) {
2794 /* if were not a real texture then read the back buffer into a real texture */
2795 /* we don't want to interfere with the back buffer so read the data into a temporary
2796 * texture and then save the data out of the temporary texture
2800 TRACE("(%p) Reading render target into texture\n", This
);
2802 glGenTextures(1, &tmpTexture
);
2803 glBindTexture(GL_TEXTURE_2D
, tmpTexture
);
2805 glTexImage2D(GL_TEXTURE_2D
,
2812 GL_UNSIGNED_INT_8_8_8_8_REV
,
2815 glGetIntegerv(GL_READ_BUFFER
, &prevRead
);
2816 checkGLcall("glGetIntegerv");
2817 glReadBuffer(swapChain
? GL_BACK
: This
->resource
.device
->offscreenBuffer
);
2818 checkGLcall("glReadBuffer");
2819 glCopyTexImage2D(GL_TEXTURE_2D
,
2828 checkGLcall("glCopyTexImage2D");
2829 glReadBuffer(prevRead
);
2832 } else { /* bind the real texture, and make sure it up to date */
2833 surface_internal_preload(iface
, SRGB_RGB
);
2834 surface_bind_and_dirtify(This
, FALSE
);
2836 allocatedMemory
= HeapAlloc(GetProcessHeap(), 0, width
* height
* 4);
2838 FIXME("Saving texture level %d width %d height %d\n", This
->texture_level
, width
, height
);
2839 glGetTexImage(GL_TEXTURE_2D
, This
->texture_level
, GL_RGBA
, GL_UNSIGNED_INT_8_8_8_8_REV
, allocatedMemory
);
2840 checkGLcall("glGetTexImage");
2842 glBindTexture(GL_TEXTURE_2D
, 0);
2843 glDeleteTextures(1, &tmpTexture
);
2847 f
= fopen(filename
, "w+");
2849 ERR("opening of %s failed with: %s\n", filename
, strerror(errno
));
2850 return WINED3DERR_INVALIDCALL
;
2852 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2853 TRACE("(%p) opened %s with format %s\n", This
, filename
, debug_d3dformat(This
->resource
.format_desc
->format
));
2868 fwrite(&width
,2,1,f
);
2870 fwrite(&height
,2,1,f
);
2875 /* 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 */
2877 textureRow
= allocatedMemory
+ (width
* (height
- 1) *4);
2879 textureRow
= allocatedMemory
;
2880 for (y
= 0 ; y
< height
; y
++) {
2881 for (i
= 0; i
< width
; i
++) {
2882 color
= *((const DWORD
*)textureRow
);
2883 fputc((color
>> 16) & 0xFF, f
); /* B */
2884 fputc((color
>> 8) & 0xFF, f
); /* G */
2885 fputc((color
>> 0) & 0xFF, f
); /* R */
2886 fputc((color
>> 24) & 0xFF, f
); /* A */
2889 /* take two rows of the pointer to the texture memory */
2891 (textureRow
-= width
<< 3);
2894 TRACE("Closing file\n");
2898 IWineD3DSwapChain_Release(swapChain
);
2900 HeapFree(GetProcessHeap(), 0, allocatedMemory
);
2904 static HRESULT WINAPI
IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface
*iface
, WINED3DFORMAT format
) {
2905 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
2908 TRACE("(%p) : Calling base function first\n", This
);
2909 hr
= IWineD3DBaseSurfaceImpl_SetFormat(iface
, format
);
2911 This
->Flags
&= ~(SFLAG_ALLOCATED
| SFLAG_SRGBALLOCATED
);
2912 TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This
, This
->resource
.format_desc
->glFormat
,
2913 This
->resource
.format_desc
->glInternal
, This
->resource
.format_desc
->glType
);
2918 static HRESULT WINAPI
IWineD3DSurfaceImpl_SetMem(IWineD3DSurface
*iface
, void *Mem
) {
2919 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
2921 if(This
->Flags
& (SFLAG_LOCKED
| SFLAG_DCINUSE
)) {
2922 WARN("Surface is locked or the HDC is in use\n");
2923 return WINED3DERR_INVALIDCALL
;
2926 if(Mem
&& Mem
!= This
->resource
.allocatedMemory
) {
2927 void *release
= NULL
;
2929 /* Do I have to copy the old surface content? */
2930 if(This
->Flags
& SFLAG_DIBSECTION
) {
2931 /* Release the DC. No need to hold the critical section for the update
2932 * Thread because this thread runs only on front buffers, but this method
2933 * fails for render targets in the check above.
2935 SelectObject(This
->hDC
, This
->dib
.holdbitmap
);
2936 DeleteDC(This
->hDC
);
2937 /* Release the DIB section */
2938 DeleteObject(This
->dib
.DIBsection
);
2939 This
->dib
.bitmap_data
= NULL
;
2940 This
->resource
.allocatedMemory
= NULL
;
2942 This
->Flags
&= ~SFLAG_DIBSECTION
;
2943 } else if(!(This
->Flags
& SFLAG_USERPTR
)) {
2944 release
= This
->resource
.heapMemory
;
2945 This
->resource
.heapMemory
= NULL
;
2947 This
->resource
.allocatedMemory
= Mem
;
2948 This
->Flags
|= SFLAG_USERPTR
| SFLAG_INSYSMEM
;
2950 /* Now the surface memory is most up do date. Invalidate drawable and texture */
2951 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, TRUE
);
2953 /* For client textures opengl has to be notified */
2954 if(This
->Flags
& SFLAG_CLIENT
) {
2955 surface_release_client_storage(iface
);
2958 /* Now free the old memory if any */
2959 HeapFree(GetProcessHeap(), 0, release
);
2960 } else if(This
->Flags
& SFLAG_USERPTR
) {
2961 /* LockRect and GetDC will re-create the dib section and allocated memory */
2962 This
->resource
.allocatedMemory
= NULL
;
2963 /* HeapMemory should be NULL already */
2964 if(This
->resource
.heapMemory
!= NULL
) ERR("User pointer surface has heap memory allocated\n");
2965 This
->Flags
&= ~SFLAG_USERPTR
;
2967 if(This
->Flags
& SFLAG_CLIENT
) {
2968 surface_release_client_storage(iface
);
2974 void flip_surface(IWineD3DSurfaceImpl
*front
, IWineD3DSurfaceImpl
*back
) {
2976 /* Flip the surface contents */
2981 front
->hDC
= back
->hDC
;
2985 /* Flip the DIBsection */
2988 BOOL hasDib
= front
->Flags
& SFLAG_DIBSECTION
;
2989 tmp
= front
->dib
.DIBsection
;
2990 front
->dib
.DIBsection
= back
->dib
.DIBsection
;
2991 back
->dib
.DIBsection
= tmp
;
2993 if(back
->Flags
& SFLAG_DIBSECTION
) front
->Flags
|= SFLAG_DIBSECTION
;
2994 else front
->Flags
&= ~SFLAG_DIBSECTION
;
2995 if(hasDib
) back
->Flags
|= SFLAG_DIBSECTION
;
2996 else back
->Flags
&= ~SFLAG_DIBSECTION
;
2999 /* Flip the surface data */
3003 tmp
= front
->dib
.bitmap_data
;
3004 front
->dib
.bitmap_data
= back
->dib
.bitmap_data
;
3005 back
->dib
.bitmap_data
= tmp
;
3007 tmp
= front
->resource
.allocatedMemory
;
3008 front
->resource
.allocatedMemory
= back
->resource
.allocatedMemory
;
3009 back
->resource
.allocatedMemory
= tmp
;
3011 tmp
= front
->resource
.heapMemory
;
3012 front
->resource
.heapMemory
= back
->resource
.heapMemory
;
3013 back
->resource
.heapMemory
= tmp
;
3018 GLuint tmp_pbo
= front
->pbo
;
3019 front
->pbo
= back
->pbo
;
3020 back
->pbo
= tmp_pbo
;
3023 /* client_memory should not be different, but just in case */
3026 tmp
= front
->dib
.client_memory
;
3027 front
->dib
.client_memory
= back
->dib
.client_memory
;
3028 back
->dib
.client_memory
= tmp
;
3031 /* Flip the opengl texture */
3035 tmp
= back
->texture_name
;
3036 back
->texture_name
= front
->texture_name
;
3037 front
->texture_name
= tmp
;
3039 tmp
= back
->texture_name_srgb
;
3040 back
->texture_name_srgb
= front
->texture_name_srgb
;
3041 front
->texture_name_srgb
= tmp
;
3045 DWORD tmp_flags
= back
->Flags
;
3046 back
->Flags
= front
->Flags
;
3047 front
->Flags
= tmp_flags
;
3051 static HRESULT WINAPI
IWineD3DSurfaceImpl_Flip(IWineD3DSurface
*iface
, IWineD3DSurface
*override
, DWORD Flags
) {
3052 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
3053 IWineD3DSwapChainImpl
*swapchain
= NULL
;
3055 TRACE("(%p)->(%p,%x)\n", This
, override
, Flags
);
3057 /* Flipping is only supported on RenderTargets and overlays*/
3058 if( !(This
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_OVERLAY
)) ) {
3059 WARN("Tried to flip a non-render target, non-overlay surface\n");
3060 return WINEDDERR_NOTFLIPPABLE
;
3063 if(This
->resource
.usage
& WINED3DUSAGE_OVERLAY
) {
3064 flip_surface(This
, (IWineD3DSurfaceImpl
*) override
);
3066 /* Update the overlay if it is visible */
3067 if(This
->overlay_dest
) {
3068 return IWineD3DSurface_DrawOverlay((IWineD3DSurface
*) This
);
3075 /* DDraw sets this for the X11 surfaces, so don't confuse the user
3076 * FIXME("(%p) Target override is not supported by now\n", This);
3077 * Additionally, it isn't really possible to support triple-buffering
3078 * properly on opengl at all
3082 IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DSwapChain
, (void **) &swapchain
);
3084 ERR("Flipped surface is not on a swapchain\n");
3085 return WINEDDERR_NOTFLIPPABLE
;
3088 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
3089 * and only d3d8 and d3d9 apps specify the presentation interval
3091 if((Flags
& (WINEDDFLIP_NOVSYNC
| WINEDDFLIP_INTERVAL2
| WINEDDFLIP_INTERVAL3
| WINEDDFLIP_INTERVAL4
)) == 0) {
3092 /* Most common case first to avoid wasting time on all the other cases */
3093 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_ONE
;
3094 } else if(Flags
& WINEDDFLIP_NOVSYNC
) {
3095 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_IMMEDIATE
;
3096 } else if(Flags
& WINEDDFLIP_INTERVAL2
) {
3097 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_TWO
;
3098 } else if(Flags
& WINEDDFLIP_INTERVAL3
) {
3099 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_THREE
;
3101 swapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_FOUR
;
3104 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
3105 hr
= IWineD3DSwapChain_Present((IWineD3DSwapChain
*) swapchain
, NULL
, NULL
, 0, NULL
, 0);
3106 IWineD3DSwapChain_Release((IWineD3DSwapChain
*) swapchain
);
3110 /* Does a direct frame buffer -> texture copy. Stretching is done
3111 * with single pixel copy calls
3113 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl
*This
, IWineD3DSurface
*SrcSurface
,
3114 const WINED3DRECT
*srect
, const WINED3DRECT
*drect
, BOOL upsidedown
, WINED3DTEXTUREFILTERTYPE Filter
)
3116 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
3119 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
3120 struct wined3d_context
*context
;
3123 context
= context_acquire(myDevice
, SrcSurface
, CTXUSAGE_BLIT
);
3124 surface_internal_preload((IWineD3DSurface
*) This
, SRGB_RGB
);
3127 /* Bind the target texture */
3128 glBindTexture(This
->texture_target
, This
->texture_name
);
3129 checkGLcall("glBindTexture");
3130 if(surface_is_offscreen(SrcSurface
)) {
3131 TRACE("Reading from an offscreen target\n");
3132 upsidedown
= !upsidedown
;
3133 glReadBuffer(myDevice
->offscreenBuffer
);
3137 glReadBuffer(surface_get_gl_buffer(SrcSurface
));
3139 checkGLcall("glReadBuffer");
3141 xrel
= (float) (srect
->x2
- srect
->x1
) / (float) (drect
->x2
- drect
->x1
);
3142 yrel
= (float) (srect
->y2
- srect
->y1
) / (float) (drect
->y2
- drect
->y1
);
3144 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3146 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3148 if(Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
) {
3149 ERR("Texture filtering not supported in direct blit\n");
3152 else if ((Filter
!= WINED3DTEXF_NONE
&& Filter
!= WINED3DTEXF_POINT
)
3153 && ((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3155 ERR("Texture filtering not supported in direct blit\n");
3159 && !((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3160 && !((yrel
- 1.0f
< -eps
) || (yrel
- 1.0f
> eps
)))
3162 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3164 glCopyTexSubImage2D(This
->texture_target
, This
->texture_level
,
3165 drect
->x1
/*xoffset */, drect
->y1
/* y offset */,
3166 srect
->x1
, Src
->currentDesc
.Height
- srect
->y2
,
3167 drect
->x2
- drect
->x1
, drect
->y2
- drect
->y1
);
3169 UINT yoffset
= Src
->currentDesc
.Height
- srect
->y1
+ drect
->y1
- 1;
3170 /* I have to process this row by row to swap the image,
3171 * otherwise it would be upside down, so stretching in y direction
3172 * doesn't cost extra time
3174 * However, stretching in x direction can be avoided if not necessary
3176 for(row
= drect
->y1
; row
< drect
->y2
; row
++) {
3177 if ((xrel
- 1.0f
< -eps
) || (xrel
- 1.0f
> eps
))
3179 /* Well, that stuff works, but it's very slow.
3180 * find a better way instead
3184 for(col
= drect
->x1
; col
< drect
->x2
; col
++) {
3185 glCopyTexSubImage2D(This
->texture_target
, This
->texture_level
,
3186 drect
->x1
+ col
/* x offset */, row
/* y offset */,
3187 srect
->x1
+ col
* xrel
, yoffset
- (int) (row
* yrel
), 1, 1);
3190 glCopyTexSubImage2D(This
->texture_target
, This
->texture_level
,
3191 drect
->x1
/* x offset */, row
/* y offset */,
3192 srect
->x1
, yoffset
- (int) (row
* yrel
), drect
->x2
-drect
->x1
, 1);
3196 checkGLcall("glCopyTexSubImage2D");
3199 context_release(context
);
3201 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3202 * path is never entered
3204 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) This
, SFLAG_INTEXTURE
, TRUE
);
3207 /* Uses the hardware to stretch and flip the image */
3208 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl
*This
, IWineD3DSurface
*SrcSurface
,
3209 IWineD3DSwapChainImpl
*swapchain
, const WINED3DRECT
*srect
, const WINED3DRECT
*drect
,
3210 BOOL upsidedown
, WINED3DTEXTUREFILTERTYPE Filter
)
3212 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
3213 GLuint src
, backup
= 0;
3214 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
3215 float left
, right
, top
, bottom
; /* Texture coordinates */
3216 UINT fbwidth
= Src
->currentDesc
.Width
;
3217 UINT fbheight
= Src
->currentDesc
.Height
;
3218 struct wined3d_context
*context
;
3219 GLenum drawBuffer
= GL_BACK
;
3220 GLenum texture_target
;
3221 BOOL noBackBufferBackup
;
3224 TRACE("Using hwstretch blit\n");
3225 /* Activate the Proper context for reading from the source surface, set it up for blitting */
3226 context
= context_acquire(myDevice
, SrcSurface
, CTXUSAGE_BLIT
);
3227 surface_internal_preload((IWineD3DSurface
*) This
, SRGB_RGB
);
3229 src_offscreen
= surface_is_offscreen(SrcSurface
);
3230 noBackBufferBackup
= src_offscreen
&& wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
;
3231 if (!noBackBufferBackup
&& !Src
->texture_name
)
3233 /* Get it a description */
3234 surface_internal_preload(SrcSurface
, SRGB_RGB
);
3238 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3239 * This way we don't have to wait for the 2nd readback to finish to leave this function.
3241 if (context
->aux_buffers
>= 2)
3243 /* Got more than one aux buffer? Use the 2nd aux buffer */
3244 drawBuffer
= GL_AUX1
;
3246 else if ((!src_offscreen
|| myDevice
->offscreenBuffer
== GL_BACK
) && context
->aux_buffers
>= 1)
3248 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3249 drawBuffer
= GL_AUX0
;
3252 if(noBackBufferBackup
) {
3253 glGenTextures(1, &backup
);
3254 checkGLcall("glGenTextures");
3255 glBindTexture(GL_TEXTURE_2D
, backup
);
3256 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3257 texture_target
= GL_TEXTURE_2D
;
3259 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3260 * we are reading from the back buffer, the backup can be used as source texture
3262 texture_target
= Src
->texture_target
;
3263 glBindTexture(texture_target
, Src
->texture_name
);
3264 checkGLcall("glBindTexture(texture_target, Src->texture_name)");
3265 glEnable(texture_target
);
3266 checkGLcall("glEnable(texture_target)");
3268 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3269 Src
->Flags
&= ~SFLAG_INTEXTURE
;
3274 TRACE("Reading from an offscreen target\n");
3275 upsidedown
= !upsidedown
;
3276 glReadBuffer(myDevice
->offscreenBuffer
);
3280 glReadBuffer(surface_get_gl_buffer(SrcSurface
));
3283 /* TODO: Only back up the part that will be overwritten */
3284 glCopyTexSubImage2D(texture_target
, 0,
3285 0, 0 /* read offsets */,
3290 checkGLcall("glCopyTexSubImage2D");
3292 /* No issue with overriding these - the sampler is dirty due to blit usage */
3293 glTexParameteri(texture_target
, GL_TEXTURE_MAG_FILTER
,
3294 wined3d_gl_mag_filter(magLookup
, Filter
));
3295 checkGLcall("glTexParameteri");
3296 glTexParameteri(texture_target
, GL_TEXTURE_MIN_FILTER
,
3297 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
3298 checkGLcall("glTexParameteri");
3300 if(!swapchain
|| (IWineD3DSurface
*) Src
== swapchain
->backBuffer
[0]) {
3301 src
= backup
? backup
: Src
->texture_name
;
3303 glReadBuffer(GL_FRONT
);
3304 checkGLcall("glReadBuffer(GL_FRONT)");
3306 glGenTextures(1, &src
);
3307 checkGLcall("glGenTextures(1, &src)");
3308 glBindTexture(GL_TEXTURE_2D
, src
);
3309 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3311 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
3312 * out for power of 2 sizes
3314 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGBA
, Src
->pow2Width
, Src
->pow2Height
, 0,
3315 GL_RGBA
, GL_UNSIGNED_BYTE
, NULL
);
3316 checkGLcall("glTexImage2D");
3317 glCopyTexSubImage2D(GL_TEXTURE_2D
, 0,
3318 0, 0 /* read offsets */,
3323 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
3324 checkGLcall("glTexParameteri");
3325 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
3326 checkGLcall("glTexParameteri");
3328 glReadBuffer(GL_BACK
);
3329 checkGLcall("glReadBuffer(GL_BACK)");
3331 if(texture_target
!= GL_TEXTURE_2D
) {
3332 glDisable(texture_target
);
3333 glEnable(GL_TEXTURE_2D
);
3334 texture_target
= GL_TEXTURE_2D
;
3337 checkGLcall("glEnd and previous");
3343 top
= Src
->currentDesc
.Height
- srect
->y1
;
3344 bottom
= Src
->currentDesc
.Height
- srect
->y2
;
3346 top
= Src
->currentDesc
.Height
- srect
->y2
;
3347 bottom
= Src
->currentDesc
.Height
- srect
->y1
;
3350 if(Src
->Flags
& SFLAG_NORMCOORD
) {
3351 left
/= Src
->pow2Width
;
3352 right
/= Src
->pow2Width
;
3353 top
/= Src
->pow2Height
;
3354 bottom
/= Src
->pow2Height
;
3357 /* draw the source texture stretched and upside down. The correct surface is bound already */
3358 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3359 glTexParameteri(texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3361 context_set_draw_buffer(context
, drawBuffer
);
3362 glReadBuffer(drawBuffer
);
3366 glTexCoord2f(left
, bottom
);
3367 glVertex2i(0, fbheight
);
3370 glTexCoord2f(left
, top
);
3371 glVertex2i(0, fbheight
- drect
->y2
- drect
->y1
);
3374 glTexCoord2f(right
, top
);
3375 glVertex2i(drect
->x2
- drect
->x1
, fbheight
- drect
->y2
- drect
->y1
);
3378 glTexCoord2f(right
, bottom
);
3379 glVertex2i(drect
->x2
- drect
->x1
, fbheight
);
3381 checkGLcall("glEnd and previous");
3383 if (texture_target
!= This
->texture_target
)
3385 glDisable(texture_target
);
3386 glEnable(This
->texture_target
);
3387 texture_target
= This
->texture_target
;
3390 /* Now read the stretched and upside down image into the destination texture */
3391 glBindTexture(texture_target
, This
->texture_name
);
3392 checkGLcall("glBindTexture");
3393 glCopyTexSubImage2D(texture_target
,
3395 drect
->x1
, drect
->y1
, /* xoffset, yoffset */
3396 0, 0, /* We blitted the image to the origin */
3397 drect
->x2
- drect
->x1
, drect
->y2
- drect
->y1
);
3398 checkGLcall("glCopyTexSubImage2D");
3400 if(drawBuffer
== GL_BACK
) {
3401 /* Write the back buffer backup back */
3403 if(texture_target
!= GL_TEXTURE_2D
) {
3404 glDisable(texture_target
);
3405 glEnable(GL_TEXTURE_2D
);
3406 texture_target
= GL_TEXTURE_2D
;
3408 glBindTexture(GL_TEXTURE_2D
, backup
);
3409 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3411 if (texture_target
!= Src
->texture_target
)
3413 glDisable(texture_target
);
3414 glEnable(Src
->texture_target
);
3415 texture_target
= Src
->texture_target
;
3417 glBindTexture(Src
->texture_target
, Src
->texture_name
);
3418 checkGLcall("glBindTexture(Src->texture_target, Src->texture_name)");
3423 glTexCoord2f(0.0f
, (float)fbheight
/ (float)Src
->pow2Height
);
3427 glTexCoord2f(0.0f
, 0.0f
);
3428 glVertex2i(0, fbheight
);
3431 glTexCoord2f((float)fbwidth
/ (float)Src
->pow2Width
, 0.0f
);
3432 glVertex2i(fbwidth
, Src
->currentDesc
.Height
);
3435 glTexCoord2f((float) fbwidth
/ (float) Src
->pow2Width
, (float) fbheight
/ (float) Src
->pow2Height
);
3436 glVertex2i(fbwidth
, 0);
3439 glDisable(texture_target
);
3440 checkGLcall("glDisable(texture_target)");
3443 if (src
!= Src
->texture_name
&& src
!= backup
)
3445 glDeleteTextures(1, &src
);
3446 checkGLcall("glDeleteTextures(1, &src)");
3449 glDeleteTextures(1, &backup
);
3450 checkGLcall("glDeleteTextures(1, &backup)");
3454 context_release(context
);
3456 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3457 * path is never entered
3459 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) This
, SFLAG_INTEXTURE
, TRUE
);
3462 /* Not called from the VTable */
3463 static HRESULT
IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl
*This
, const RECT
*DestRect
,
3464 IWineD3DSurface
*SrcSurface
, const RECT
*SrcRect
, DWORD Flags
, const WINEDDBLTFX
*DDBltFx
,
3465 WINED3DTEXTUREFILTERTYPE Filter
)
3467 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
3469 IWineD3DSwapChainImpl
*srcSwapchain
= NULL
, *dstSwapchain
= NULL
;
3470 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
3472 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
3474 /* Get the swapchain. One of the surfaces has to be a primary surface */
3475 if(This
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
) {
3476 WARN("Destination is in sysmem, rejecting gl blt\n");
3477 return WINED3DERR_INVALIDCALL
;
3479 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) This
, &IID_IWineD3DSwapChain
, (void **)&dstSwapchain
);
3480 if(dstSwapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) dstSwapchain
);
3482 if(Src
->resource
.pool
== WINED3DPOOL_SYSTEMMEM
) {
3483 WARN("Src is in sysmem, rejecting gl blt\n");
3484 return WINED3DERR_INVALIDCALL
;
3486 IWineD3DSurface_GetContainer( (IWineD3DSurface
*) Src
, &IID_IWineD3DSwapChain
, (void **)&srcSwapchain
);
3487 if(srcSwapchain
) IWineD3DSwapChain_Release((IWineD3DSwapChain
*) srcSwapchain
);
3490 /* Early sort out of cases where no render target is used */
3491 if(!dstSwapchain
&& !srcSwapchain
&&
3492 SrcSurface
!= myDevice
->render_targets
[0] && This
!= (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0]) {
3493 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src
, This
);
3494 return WINED3DERR_INVALIDCALL
;
3497 /* No destination color keying supported */
3498 if(Flags
& (WINEDDBLT_KEYDEST
| WINEDDBLT_KEYDESTOVERRIDE
)) {
3499 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3500 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3501 return WINED3DERR_INVALIDCALL
;
3505 rect
.x1
= DestRect
->left
;
3506 rect
.y1
= DestRect
->top
;
3507 rect
.x2
= DestRect
->right
;
3508 rect
.y2
= DestRect
->bottom
;
3512 rect
.x2
= This
->currentDesc
.Width
;
3513 rect
.y2
= This
->currentDesc
.Height
;
3516 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3517 if(dstSwapchain
&& dstSwapchain
== srcSwapchain
&& dstSwapchain
->backBuffer
&&
3518 ((IWineD3DSurface
*) This
== dstSwapchain
->frontBuffer
) && SrcSurface
== dstSwapchain
->backBuffer
[0]) {
3519 /* Half-life does a Blt from the back buffer to the front buffer,
3520 * Full surface size, no flags... Use present instead
3522 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3525 /* Check rects - IWineD3DDevice_Present doesn't handle them */
3529 TRACE("Looking if a Present can be done...\n");
3530 /* Source Rectangle must be full surface */
3532 if(SrcRect
->left
!= 0 || SrcRect
->top
!= 0 ||
3533 SrcRect
->right
!= Src
->currentDesc
.Width
|| SrcRect
->bottom
!= Src
->currentDesc
.Height
) {
3534 TRACE("No, Source rectangle doesn't match\n");
3540 mySrcRect
.right
= Src
->currentDesc
.Width
;
3541 mySrcRect
.bottom
= Src
->currentDesc
.Height
;
3543 /* No stretching may occur */
3544 if(mySrcRect
.right
!= rect
.x2
- rect
.x1
||
3545 mySrcRect
.bottom
!= rect
.y2
- rect
.y1
) {
3546 TRACE("No, stretching is done\n");
3550 /* Destination must be full surface or match the clipping rectangle */
3551 if(This
->clipper
&& ((IWineD3DClipperImpl
*) This
->clipper
)->hWnd
)
3555 GetClientRect(((IWineD3DClipperImpl
*) This
->clipper
)->hWnd
, &cliprect
);
3560 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl
*) This
->clipper
)->hWnd
,
3563 if(pos
[0].x
!= cliprect
.left
|| pos
[0].y
!= cliprect
.top
||
3564 pos
[1].x
!= cliprect
.right
|| pos
[1].y
!= cliprect
.bottom
)
3566 TRACE("No, dest rectangle doesn't match(clipper)\n");
3567 TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect
.left
, cliprect
.top
, cliprect
.right
, cliprect
.bottom
);
3568 TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect
.x1
, rect
.y1
, rect
.x2
, rect
.y2
);
3574 if(rect
.x1
!= 0 || rect
.y1
!= 0 ||
3575 rect
.x2
!= This
->currentDesc
.Width
|| rect
.y2
!= This
->currentDesc
.Height
) {
3576 TRACE("No, dest rectangle doesn't match(surface size)\n");
3583 /* These flags are unimportant for the flag check, remove them */
3584 if((Flags
& ~(WINEDDBLT_DONOTWAIT
| WINEDDBLT_WAIT
)) == 0) {
3585 WINED3DSWAPEFFECT orig_swap
= dstSwapchain
->presentParms
.SwapEffect
;
3587 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3588 * take very long, while a flip is fast.
3589 * This applies to Half-Life, which does such Blts every time it finished
3590 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3591 * menu. This is also used by all apps when they do windowed rendering
3593 * The problem is that flipping is not really the same as copying. After a
3594 * Blt the front buffer is a copy of the back buffer, and the back buffer is
3595 * untouched. Therefore it's necessary to override the swap effect
3596 * and to set it back after the flip.
3598 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3602 dstSwapchain
->presentParms
.SwapEffect
= WINED3DSWAPEFFECT_COPY
;
3603 dstSwapchain
->presentParms
.PresentationInterval
= WINED3DPRESENT_INTERVAL_IMMEDIATE
;
3605 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3606 IWineD3DSwapChain_Present((IWineD3DSwapChain
*) dstSwapchain
, NULL
, NULL
, 0, NULL
, 0);
3608 dstSwapchain
->presentParms
.SwapEffect
= orig_swap
;
3615 TRACE("Unsupported blit between buffers on the same swapchain\n");
3616 return WINED3DERR_INVALIDCALL
;
3617 } else if(dstSwapchain
&& dstSwapchain
== srcSwapchain
) {
3618 FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3619 return WINED3DERR_INVALIDCALL
;
3620 } else if(dstSwapchain
&& srcSwapchain
) {
3621 FIXME("Implement hardware blit between two different swapchains\n");
3622 return WINED3DERR_INVALIDCALL
;
3623 } else if(dstSwapchain
) {
3624 if(SrcSurface
== myDevice
->render_targets
[0]) {
3625 TRACE("Blit from active render target to a swapchain\n");
3626 /* Handled with regular texture -> swapchain blit */
3628 } else if(srcSwapchain
&& This
== (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0]) {
3629 FIXME("Implement blit from a swapchain to the active render target\n");
3630 return WINED3DERR_INVALIDCALL
;
3633 if((srcSwapchain
|| SrcSurface
== myDevice
->render_targets
[0]) && !dstSwapchain
) {
3634 /* Blit from render target to texture */
3636 BOOL upsideDown
, stretchx
;
3637 BOOL paletteOverride
= FALSE
;
3639 if(Flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
)) {
3640 TRACE("Color keying not supported by frame buffer to texture blit\n");
3641 return WINED3DERR_INVALIDCALL
;
3642 /* Destination color key is checked above */
3645 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3646 * glCopyTexSubImage is a bit picky about the parameters we pass to it
3649 if(SrcRect
->top
< SrcRect
->bottom
) {
3650 srect
.y1
= SrcRect
->top
;
3651 srect
.y2
= SrcRect
->bottom
;
3654 srect
.y1
= SrcRect
->bottom
;
3655 srect
.y2
= SrcRect
->top
;
3658 srect
.x1
= SrcRect
->left
;
3659 srect
.x2
= SrcRect
->right
;
3663 srect
.x2
= Src
->currentDesc
.Width
;
3664 srect
.y2
= Src
->currentDesc
.Height
;
3667 if(rect
.x1
> rect
.x2
) {
3671 upsideDown
= !upsideDown
;
3674 if(rect
.x2
- rect
.x1
!= srect
.x2
- srect
.x1
) {
3680 /* When blitting from a render target a texture, the texture isn't required to have a palette.
3681 * In this case grab the palette from the render target. */
3682 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
&& !This
->palette
)
3684 paletteOverride
= TRUE
;
3685 TRACE("Source surface (%p) lacks palette, overriding palette with palette %p of destination surface (%p)\n", Src
, This
->palette
, This
);
3686 This
->palette
= Src
->palette
;
3689 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3690 * flip the image nor scale it.
3692 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3693 * -> If the app wants a image width an unscaled width, copy it line per line
3694 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3695 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3696 * back buffer. This is slower than reading line per line, thus not used for flipping
3697 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3700 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3701 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3704 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
3705 && myDevice
->adapter
->gl_info
.fbo_ops
.glBlitFramebuffer
3706 && surface_can_stretch_rect(Src
, This
))
3708 stretch_rect_fbo((IWineD3DDevice
*)myDevice
, SrcSurface
, &srect
,
3709 (IWineD3DSurface
*)This
, &rect
, Filter
, upsideDown
);
3710 } else if((!stretchx
) || rect
.x2
- rect
.x1
> Src
->currentDesc
.Width
||
3711 rect
.y2
- rect
.y1
> Src
->currentDesc
.Height
) {
3712 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3713 fb_copy_to_texture_direct(This
, SrcSurface
, &srect
, &rect
, upsideDown
, Filter
);
3715 TRACE("Using hardware stretching to flip / stretch the texture\n");
3716 fb_copy_to_texture_hwstretch(This
, SrcSurface
, srcSwapchain
, &srect
, &rect
, upsideDown
, Filter
);
3719 /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
3721 This
->palette
= NULL
;
3723 if(!(This
->Flags
& SFLAG_DONOTFREE
)) {
3724 HeapFree(GetProcessHeap(), 0, This
->resource
.heapMemory
);
3725 This
->resource
.allocatedMemory
= NULL
;
3726 This
->resource
.heapMemory
= NULL
;
3728 This
->Flags
&= ~SFLAG_INSYSMEM
;
3733 /* Blit from offscreen surface to render target */
3734 float glTexCoord
[4];
3735 DWORD oldCKeyFlags
= Src
->CKeyFlags
;
3736 WINEDDCOLORKEY oldBltCKey
= Src
->SrcBltCKey
;
3737 struct wined3d_context
*context
;
3738 RECT SourceRectangle
;
3739 BOOL paletteOverride
= FALSE
;
3741 TRACE("Blt from surface %p to rendertarget %p\n", Src
, This
);
3744 SourceRectangle
.left
= SrcRect
->left
;
3745 SourceRectangle
.right
= SrcRect
->right
;
3746 SourceRectangle
.top
= SrcRect
->top
;
3747 SourceRectangle
.bottom
= SrcRect
->bottom
;
3749 SourceRectangle
.left
= 0;
3750 SourceRectangle
.right
= Src
->currentDesc
.Width
;
3751 SourceRectangle
.top
= 0;
3752 SourceRectangle
.bottom
= Src
->currentDesc
.Height
;
3755 /* When blitting from an offscreen surface to a rendertarget, the source
3756 * surface is not required to have a palette. Our rendering / conversion
3757 * code further down the road retrieves the palette from the surface, so
3758 * it must have a palette set. */
3759 if (Src
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
&& !Src
->palette
)
3761 paletteOverride
= TRUE
;
3762 TRACE("Source surface (%p) lacks palette, overriding palette with palette %p of destination surface (%p)\n", Src
, This
->palette
, This
);
3763 Src
->palette
= This
->palette
;
3766 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
3767 && myDevice
->adapter
->gl_info
.fbo_ops
.glBlitFramebuffer
3768 && !(Flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
))
3769 && surface_can_stretch_rect(Src
, This
))
3771 TRACE("Using stretch_rect_fbo\n");
3772 /* The source is always a texture, but never the currently active render target, and the texture
3773 * contents are never upside down
3775 stretch_rect_fbo((IWineD3DDevice
*)myDevice
, SrcSurface
, (WINED3DRECT
*) &SourceRectangle
,
3776 (IWineD3DSurface
*)This
, &rect
, Filter
, FALSE
);
3778 /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
3780 Src
->palette
= NULL
;
3784 if(!CalculateTexRect(Src
, &SourceRectangle
, glTexCoord
)) {
3785 /* Fall back to software */
3786 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src
,
3787 SourceRectangle
.left
, SourceRectangle
.top
,
3788 SourceRectangle
.right
, SourceRectangle
.bottom
);
3789 return WINED3DERR_INVALIDCALL
;
3792 /* Color keying: Check if we have to do a color keyed blt,
3793 * and if not check if a color key is activated.
3795 * Just modify the color keying parameters in the surface and restore them afterwards
3796 * The surface keeps track of the color key last used to load the opengl surface.
3797 * PreLoad will catch the change to the flags and color key and reload if necessary.
3799 if(Flags
& WINEDDBLT_KEYSRC
) {
3800 /* Use color key from surface */
3801 } else if(Flags
& WINEDDBLT_KEYSRCOVERRIDE
) {
3802 /* Use color key from DDBltFx */
3803 Src
->CKeyFlags
|= WINEDDSD_CKSRCBLT
;
3804 Src
->SrcBltCKey
= DDBltFx
->ddckSrcColorkey
;
3806 /* Do not use color key */
3807 Src
->CKeyFlags
&= ~WINEDDSD_CKSRCBLT
;
3810 /* Now load the surface */
3811 surface_internal_preload((IWineD3DSurface
*) Src
, SRGB_RGB
);
3813 /* Activate the destination context, set it up for blitting */
3814 context
= context_acquire(myDevice
, (IWineD3DSurface
*)This
, CTXUSAGE_BLIT
);
3816 /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
3817 * while OpenGL coordinates are window relative.
3818 * Also beware of the origin difference(top left vs bottom left).
3819 * Also beware that the front buffer's surface size is screen width x screen height,
3820 * whereas the real gl drawable size is the size of the window.
3822 if (dstSwapchain
&& (IWineD3DSurface
*)This
== dstSwapchain
->frontBuffer
) {
3824 POINT offset
= {0,0};
3826 ClientToScreen(dstSwapchain
->win_handle
, &offset
);
3827 GetClientRect(dstSwapchain
->win_handle
, &windowsize
);
3828 h
= windowsize
.bottom
- windowsize
.top
;
3829 rect
.x1
-= offset
.x
; rect
.x2
-=offset
.x
;
3830 rect
.y1
-= offset
.y
; rect
.y2
-=offset
.y
;
3831 rect
.y1
+= This
->currentDesc
.Height
- h
; rect
.y2
+= This
->currentDesc
.Height
- h
;
3834 if (!is_identity_fixup(This
->resource
.format_desc
->color_fixup
))
3836 FIXME("Destination format %s has a fixup, this is not supported.\n",
3837 debug_d3dformat(This
->resource
.format_desc
->format
));
3838 dump_color_fixup_desc(This
->resource
.format_desc
->color_fixup
);
3841 if (!myDevice
->blitter
->color_fixup_supported(Src
->resource
.format_desc
->color_fixup
))
3843 FIXME("Source format %s has an unsupported fixup:\n",
3844 debug_d3dformat(Src
->resource
.format_desc
->format
));
3845 dump_color_fixup_desc(Src
->resource
.format_desc
->color_fixup
);
3848 myDevice
->blitter
->set_shader((IWineD3DDevice
*) myDevice
, Src
->resource
.format_desc
,
3849 Src
->texture_target
, Src
->pow2Width
, Src
->pow2Height
);
3853 /* Bind the texture */
3854 glBindTexture(Src
->texture_target
, Src
->texture_name
);
3855 checkGLcall("glBindTexture");
3857 /* Filtering for StretchRect */
3858 glTexParameteri(Src
->texture_target
, GL_TEXTURE_MAG_FILTER
,
3859 wined3d_gl_mag_filter(magLookup
, Filter
));
3860 checkGLcall("glTexParameteri");
3861 glTexParameteri(Src
->texture_target
, GL_TEXTURE_MIN_FILTER
,
3862 wined3d_gl_min_mip_filter(minMipLookup
, Filter
, WINED3DTEXF_NONE
));
3863 checkGLcall("glTexParameteri");
3864 glTexParameteri(Src
->texture_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP
);
3865 glTexParameteri(Src
->texture_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP
);
3866 glTexEnvi(GL_TEXTURE_ENV
, GL_TEXTURE_ENV_MODE
, GL_REPLACE
);
3867 checkGLcall("glTexEnvi");
3869 /* This is for color keying */
3870 if(Flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
)) {
3871 glEnable(GL_ALPHA_TEST
);
3872 checkGLcall("glEnable(GL_ALPHA_TEST)");
3874 /* When the primary render target uses P8, the alpha component contains the palette index.
3875 * Which means that the colorkey is one of the palette entries. In other cases pixels that
3876 * should be masked away have alpha set to 0. */
3877 if(primary_render_target_is_p8(myDevice
))
3878 glAlphaFunc(GL_NOTEQUAL
, (float)Src
->SrcBltCKey
.dwColorSpaceLowValue
/ 256.0f
);
3880 glAlphaFunc(GL_NOTEQUAL
, 0.0f
);
3881 checkGLcall("glAlphaFunc");
3883 glDisable(GL_ALPHA_TEST
);
3884 checkGLcall("glDisable(GL_ALPHA_TEST)");
3887 /* Draw a textured quad
3891 glColor3f(1.0f
, 1.0f
, 1.0f
);
3892 glTexCoord2f(glTexCoord
[0], glTexCoord
[2]);
3893 glVertex3f(rect
.x1
, rect
.y1
, 0.0f
);
3895 glTexCoord2f(glTexCoord
[0], glTexCoord
[3]);
3896 glVertex3f(rect
.x1
, rect
.y2
, 0.0f
);
3898 glTexCoord2f(glTexCoord
[1], glTexCoord
[3]);
3899 glVertex3f(rect
.x2
, rect
.y2
, 0.0f
);
3901 glTexCoord2f(glTexCoord
[1], glTexCoord
[2]);
3902 glVertex3f(rect
.x2
, rect
.y1
, 0.0f
);
3905 checkGLcall("glEnd");
3907 if(Flags
& (WINEDDBLT_KEYSRC
| WINEDDBLT_KEYSRCOVERRIDE
)) {
3908 glDisable(GL_ALPHA_TEST
);
3909 checkGLcall("glDisable(GL_ALPHA_TEST)");
3912 glBindTexture(Src
->texture_target
, 0);
3913 checkGLcall("glBindTexture(Src->texture_target, 0)");
3915 /* Restore the color key parameters */
3916 Src
->CKeyFlags
= oldCKeyFlags
;
3917 Src
->SrcBltCKey
= oldBltCKey
;
3919 /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
3921 Src
->palette
= NULL
;
3925 /* Leave the opengl state valid for blitting */
3926 myDevice
->blitter
->unset_shader((IWineD3DDevice
*) myDevice
);
3928 /* Flush in case the drawable is used by multiple GL contexts */
3929 if(dstSwapchain
&& (This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->frontBuffer
|| dstSwapchain
->num_contexts
>= 2))
3932 context_release(context
);
3934 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3935 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3938 IWineD3DSurface_ModifyLocation((IWineD3DSurface
*) This
, SFLAG_INDRAWABLE
, TRUE
);
3942 /* Source-Less Blit to render target */
3943 if (Flags
& WINEDDBLT_COLORFILL
) {
3944 /* This is easy to handle for the D3D Device... */
3947 TRACE("Colorfill\n");
3949 /* This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0] || dstSwapchain
3950 must be true if we are here */
3951 if (This
!= (IWineD3DSurfaceImpl
*) myDevice
->render_targets
[0] &&
3952 !(This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->frontBuffer
||
3953 (dstSwapchain
->backBuffer
&& This
== (IWineD3DSurfaceImpl
*) dstSwapchain
->backBuffer
[0]))) {
3954 TRACE("Surface is higher back buffer, falling back to software\n");
3955 return WINED3DERR_INVALIDCALL
;
3958 /* The color as given in the Blt function is in the format of the frame-buffer...
3959 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3961 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
)
3965 if (primary_render_target_is_p8(myDevice
)) alpha
= DDBltFx
->u5
.dwFillColor
<< 24;
3966 else alpha
= 0xFF000000;
3968 if (This
->palette
) {
3970 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peRed
<< 16) |
3971 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peGreen
<< 8) |
3972 (This
->palette
->palents
[DDBltFx
->u5
.dwFillColor
].peBlue
));
3977 else if (This
->resource
.format_desc
->format
== WINED3DFMT_B5G6R5_UNORM
)
3979 if (DDBltFx
->u5
.dwFillColor
== 0xFFFF) {
3982 color
= ((0xFF000000) |
3983 ((DDBltFx
->u5
.dwFillColor
& 0xF800) << 8) |
3984 ((DDBltFx
->u5
.dwFillColor
& 0x07E0) << 5) |
3985 ((DDBltFx
->u5
.dwFillColor
& 0x001F) << 3));
3988 else if (This
->resource
.format_desc
->format
== WINED3DFMT_B8G8R8_UNORM
3989 || This
->resource
.format_desc
->format
== WINED3DFMT_B8G8R8X8_UNORM
)
3991 color
= 0xFF000000 | DDBltFx
->u5
.dwFillColor
;
3993 else if (This
->resource
.format_desc
->format
== WINED3DFMT_B8G8R8A8_UNORM
)
3995 color
= DDBltFx
->u5
.dwFillColor
;
3998 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
3999 return WINED3DERR_INVALIDCALL
;
4002 TRACE("(%p) executing Render Target override, color = %x\n", This
, color
);
4003 IWineD3DDeviceImpl_ClearSurface(myDevice
, This
, 1 /* Number of rectangles */,
4004 &rect
, WINED3DCLEAR_TARGET
, color
, 0.0f
/* Z */, 0 /* Stencil */);
4009 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4010 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4011 return WINED3DERR_INVALIDCALL
;
4014 static HRESULT
IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl
*This
, const RECT
*DestRect
,
4015 IWineD3DSurface
*SrcSurface
, const RECT
*SrcRect
, DWORD Flags
, const WINEDDBLTFX
*DDBltFx
)
4017 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
4020 if (Flags
& WINEDDBLT_DEPTHFILL
) {
4021 switch(This
->resource
.format_desc
->format
)
4023 case WINED3DFMT_D16_UNORM
:
4024 depth
= (float) DDBltFx
->u5
.dwFillDepth
/ (float) 0x0000ffff;
4026 case WINED3DFMT_S1_UINT_D15_UNORM
:
4027 depth
= (float) DDBltFx
->u5
.dwFillDepth
/ (float) 0x0000fffe;
4029 case WINED3DFMT_D24_UNORM_S8_UINT
:
4030 case WINED3DFMT_X8D24_UNORM
:
4031 depth
= (float) DDBltFx
->u5
.dwFillDepth
/ (float) 0x00ffffff;
4033 case WINED3DFMT_D32_UNORM
:
4034 depth
= (float) DDBltFx
->u5
.dwFillDepth
/ (float) 0xffffffff;
4038 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This
->resource
.format_desc
->format
));
4041 return IWineD3DDevice_Clear((IWineD3DDevice
*) myDevice
,
4042 DestRect
== NULL
? 0 : 1,
4043 (const WINED3DRECT
*)DestRect
,
4044 WINED3DCLEAR_ZBUFFER
,
4050 FIXME("(%p): Unsupp depthstencil blit\n", This
);
4051 return WINED3DERR_INVALIDCALL
;
4054 static HRESULT WINAPI
IWineD3DSurfaceImpl_Blt(IWineD3DSurface
*iface
, const RECT
*DestRect
, IWineD3DSurface
*SrcSurface
,
4055 const RECT
*SrcRect
, DWORD Flags
, const WINEDDBLTFX
*DDBltFx
, WINED3DTEXTUREFILTERTYPE Filter
) {
4056 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
4057 IWineD3DSurfaceImpl
*Src
= (IWineD3DSurfaceImpl
*) SrcSurface
;
4058 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
4060 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
);
4061 TRACE("(%p): Usage is %s\n", This
, debug_d3dusage(This
->resource
.usage
));
4063 if ( (This
->Flags
& SFLAG_LOCKED
) || ((Src
!= NULL
) && (Src
->Flags
& SFLAG_LOCKED
)))
4065 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4066 return WINEDDERR_SURFACEBUSY
;
4069 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
4070 * except depth blits, which seem to work
4072 if(iface
== myDevice
->stencilBufferTarget
|| (SrcSurface
&& SrcSurface
== myDevice
->stencilBufferTarget
)) {
4073 if(myDevice
->inScene
&& !(Flags
& WINEDDBLT_DEPTHFILL
)) {
4074 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4075 return WINED3DERR_INVALIDCALL
;
4076 } else if(IWineD3DSurfaceImpl_BltZ(This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
) == WINED3D_OK
) {
4077 TRACE("Z Blit override handled the blit\n");
4082 /* Special cases for RenderTargets */
4083 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
4084 ( Src
&& (Src
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) )) {
4085 if(IWineD3DSurfaceImpl_BltOverride(This
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
, Filter
) == WINED3D_OK
) return WINED3D_OK
;
4088 /* For the rest call the X11 surface implementation.
4089 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
4090 * other Blts are rather rare
4092 return IWineD3DBaseSurfaceImpl_Blt(iface
, DestRect
, SrcSurface
, SrcRect
, Flags
, DDBltFx
, Filter
);
4095 static HRESULT WINAPI
IWineD3DSurfaceImpl_BltFast(IWineD3DSurface
*iface
, DWORD dstx
, DWORD dsty
,
4096 IWineD3DSurface
*Source
, const RECT
*rsrc
, DWORD trans
)
4098 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
4099 IWineD3DSurfaceImpl
*srcImpl
= (IWineD3DSurfaceImpl
*) Source
;
4100 IWineD3DDeviceImpl
*myDevice
= This
->resource
.device
;
4102 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface
, dstx
, dsty
, Source
, rsrc
, trans
);
4104 if ( (This
->Flags
& SFLAG_LOCKED
) || (srcImpl
->Flags
& SFLAG_LOCKED
))
4106 WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4107 return WINEDDERR_SURFACEBUSY
;
4110 if(myDevice
->inScene
&&
4111 (iface
== myDevice
->stencilBufferTarget
||
4112 (Source
== myDevice
->stencilBufferTarget
))) {
4113 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4114 return WINED3DERR_INVALIDCALL
;
4117 /* Special cases for RenderTargets */
4118 if( (This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ||
4119 (srcImpl
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) ) {
4121 RECT SrcRect
, DstRect
;
4125 SrcRect
.left
= rsrc
->left
;
4126 SrcRect
.top
= rsrc
->top
;
4127 SrcRect
.bottom
= rsrc
->bottom
;
4128 SrcRect
.right
= rsrc
->right
;
4132 SrcRect
.right
= srcImpl
->currentDesc
.Width
;
4133 SrcRect
.bottom
= srcImpl
->currentDesc
.Height
;
4136 DstRect
.left
= dstx
;
4138 DstRect
.right
= dstx
+ SrcRect
.right
- SrcRect
.left
;
4139 DstRect
.bottom
= dsty
+ SrcRect
.bottom
- SrcRect
.top
;
4141 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
4142 if(trans
& WINEDDBLTFAST_SRCCOLORKEY
)
4143 Flags
|= WINEDDBLT_KEYSRC
;
4144 if(trans
& WINEDDBLTFAST_DESTCOLORKEY
)
4145 Flags
|= WINEDDBLT_KEYDEST
;
4146 if(trans
& WINEDDBLTFAST_WAIT
)
4147 Flags
|= WINEDDBLT_WAIT
;
4148 if(trans
& WINEDDBLTFAST_DONOTWAIT
)
4149 Flags
|= WINEDDBLT_DONOTWAIT
;
4151 if(IWineD3DSurfaceImpl_BltOverride(This
, &DstRect
, Source
, &SrcRect
, Flags
, NULL
, WINED3DTEXF_POINT
) == WINED3D_OK
) return WINED3D_OK
;
4155 return IWineD3DBaseSurfaceImpl_BltFast(iface
, dstx
, dsty
, Source
, rsrc
, trans
);
4158 static HRESULT WINAPI
IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface
*iface
)
4160 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
4162 IWineD3DPaletteImpl
*pal
= This
->palette
;
4164 TRACE("(%p)\n", This
);
4166 if (!pal
) return WINED3D_OK
;
4168 if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4169 || This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT_A8_UNORM
)
4172 GLenum format
, internal
, type
;
4173 CONVERT_TYPES convert
;
4175 /* Check if we are using a RTL mode which uses texturing for uploads */
4176 BOOL use_texture
= (wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
);
4178 /* Check if we have hardware palette conversion if we have convert is set to NO_CONVERSION */
4179 d3dfmt_get_conv(This
, TRUE
, use_texture
, &format
, &internal
, &type
, &convert
, &bpp
, FALSE
);
4181 if((This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) && (convert
== NO_CONVERSION
))
4183 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
4184 struct wined3d_context
*context
;
4186 /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
4187 IWineD3DSurface_LoadLocation(iface
, SFLAG_INTEXTURE
, NULL
);
4189 /* We want to force a palette refresh, so mark the drawable as not being up to date */
4190 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INDRAWABLE
, FALSE
);
4192 /* Re-upload the palette */
4193 context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
4194 d3dfmt_p8_upload_palette(iface
, convert
);
4195 context_release(context
);
4197 if(!(This
->Flags
& SFLAG_INSYSMEM
)) {
4198 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
4199 IWineD3DSurface_LoadLocation(iface
, SFLAG_INSYSMEM
, NULL
);
4201 TRACE("Dirtifying surface\n");
4202 IWineD3DSurface_ModifyLocation(iface
, SFLAG_INSYSMEM
, TRUE
);
4206 if(This
->Flags
& SFLAG_DIBSECTION
) {
4207 TRACE("(%p): Updating the hdc's palette\n", This
);
4208 for (n
=0; n
<256; n
++) {
4209 col
[n
].rgbRed
= pal
->palents
[n
].peRed
;
4210 col
[n
].rgbGreen
= pal
->palents
[n
].peGreen
;
4211 col
[n
].rgbBlue
= pal
->palents
[n
].peBlue
;
4212 col
[n
].rgbReserved
= 0;
4214 SetDIBColorTable(This
->hDC
, 0, 256, col
);
4217 /* Propagate the changes to the drawable when we have a palette. */
4218 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
)
4219 IWineD3DSurface_LoadLocation(iface
, SFLAG_INDRAWABLE
, NULL
);
4224 static HRESULT WINAPI
IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface
*iface
) {
4225 /** Check against the maximum texture sizes supported by the video card **/
4226 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
4227 const struct wined3d_gl_info
*gl_info
= &This
->resource
.device
->adapter
->gl_info
;
4228 unsigned int pow2Width
, pow2Height
;
4230 This
->texture_name
= 0;
4231 This
->texture_target
= GL_TEXTURE_2D
;
4233 /* Non-power2 support */
4234 if (gl_info
->supported
[ARB_TEXTURE_NON_POWER_OF_TWO
] || gl_info
->supported
[WINE_NORMALIZED_TEXRECT
])
4236 pow2Width
= This
->currentDesc
.Width
;
4237 pow2Height
= This
->currentDesc
.Height
;
4241 /* Find the nearest pow2 match */
4242 pow2Width
= pow2Height
= 1;
4243 while (pow2Width
< This
->currentDesc
.Width
) pow2Width
<<= 1;
4244 while (pow2Height
< This
->currentDesc
.Height
) pow2Height
<<= 1;
4246 This
->pow2Width
= pow2Width
;
4247 This
->pow2Height
= pow2Height
;
4249 if (pow2Width
> This
->currentDesc
.Width
|| pow2Height
> This
->currentDesc
.Height
) {
4250 /** TODO: add support for non power two compressed textures **/
4251 if (This
->resource
.format_desc
->Flags
& WINED3DFMT_FLAG_COMPRESSED
)
4253 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
4254 This
, This
->currentDesc
.Width
, This
->currentDesc
.Height
);
4255 return WINED3DERR_NOTAVAILABLE
;
4259 if(pow2Width
!= This
->currentDesc
.Width
||
4260 pow2Height
!= This
->currentDesc
.Height
) {
4261 This
->Flags
|= SFLAG_NONPOW2
;
4264 TRACE("%p\n", This
);
4265 if ((This
->pow2Width
> gl_info
->limits
.texture_size
|| This
->pow2Height
> gl_info
->limits
.texture_size
)
4266 && !(This
->resource
.usage
& (WINED3DUSAGE_RENDERTARGET
| WINED3DUSAGE_DEPTHSTENCIL
)))
4268 /* one of three options
4269 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)
4270 2: Set the texture to the maximum size (bad idea)
4271 3: WARN and return WINED3DERR_NOTAVAILABLE;
4272 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.
4274 WARN("(%p) Creating an oversized surface: %ux%u (texture is %ux%u)\n",
4275 This
, This
->pow2Width
, This
->pow2Height
, This
->currentDesc
.Width
, This
->currentDesc
.Height
);
4276 This
->Flags
|= SFLAG_OVERSIZE
;
4278 /* This will be initialized on the first blt */
4279 This
->glRect
.left
= 0;
4280 This
->glRect
.top
= 0;
4281 This
->glRect
.right
= 0;
4282 This
->glRect
.bottom
= 0;
4284 /* Check this after the oversize check - do not make an oversized surface a texture_rectangle one.
4285 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4286 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4287 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4289 if (This
->Flags
& SFLAG_NONPOW2
&& gl_info
->supported
[ARB_TEXTURE_RECTANGLE
]
4290 && !(This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
4291 && gl_info
->supported
[EXT_PALETTED_TEXTURE
]
4292 && wined3d_settings
.rendertargetlock_mode
== RTL_READTEX
))
4294 This
->texture_target
= GL_TEXTURE_RECTANGLE_ARB
;
4295 This
->pow2Width
= This
->currentDesc
.Width
;
4296 This
->pow2Height
= This
->currentDesc
.Height
;
4297 This
->Flags
&= ~(SFLAG_NONPOW2
| SFLAG_NORMCOORD
);
4300 /* No oversize, gl rect is the full texture size */
4301 This
->Flags
&= ~SFLAG_OVERSIZE
;
4302 This
->glRect
.left
= 0;
4303 This
->glRect
.top
= 0;
4304 This
->glRect
.right
= This
->pow2Width
;
4305 This
->glRect
.bottom
= This
->pow2Height
;
4308 if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
4309 switch(wined3d_settings
.offscreen_rendering_mode
) {
4310 case ORM_FBO
: This
->get_drawable_size
= get_drawable_size_fbo
; break;
4311 case ORM_PBUFFER
: This
->get_drawable_size
= get_drawable_size_pbuffer
; break;
4312 case ORM_BACKBUFFER
: This
->get_drawable_size
= get_drawable_size_backbuffer
; break;
4316 This
->Flags
|= SFLAG_INSYSMEM
;
4321 struct depth_blt_info
4325 enum tex_types tex_type
;
4326 GLfloat coords
[4][3];
4329 static void surface_get_depth_blt_info(GLenum target
, GLsizei w
, GLsizei h
, struct depth_blt_info
*info
)
4331 GLfloat (*coords
)[3] = info
->coords
;
4336 FIXME("Unsupported texture target %#x\n", target
);
4337 /* Fall back to GL_TEXTURE_2D */
4339 info
->binding
= GL_TEXTURE_BINDING_2D
;
4340 info
->bind_target
= GL_TEXTURE_2D
;
4341 info
->tex_type
= tex_2d
;
4342 coords
[0][0] = 0.0f
; coords
[0][1] = 1.0f
; coords
[0][2] = 0.0f
;
4343 coords
[1][0] = 1.0f
; coords
[1][1] = 1.0f
; coords
[1][2] = 0.0f
;
4344 coords
[2][0] = 0.0f
; coords
[2][1] = 0.0f
; coords
[2][2] = 0.0f
;
4345 coords
[3][0] = 1.0f
; coords
[3][1] = 0.0f
; coords
[3][2] = 0.0f
;
4348 case GL_TEXTURE_RECTANGLE_ARB
:
4349 info
->binding
= GL_TEXTURE_BINDING_RECTANGLE_ARB
;
4350 info
->bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4351 info
->tex_type
= tex_rect
;
4352 coords
[0][0] = 0.0f
; coords
[0][1] = h
; coords
[0][2] = 0.0f
;
4353 coords
[1][0] = w
; coords
[1][1] = h
; coords
[1][2] = 0.0f
;
4354 coords
[2][0] = 0.0f
; coords
[2][1] = 0.0f
; coords
[2][2] = 0.0f
;
4355 coords
[3][0] = w
; coords
[3][1] = 0.0f
; coords
[3][2] = 0.0f
;
4358 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
4359 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4360 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4361 info
->tex_type
= tex_cube
;
4362 coords
[0][0] = 1.0f
; coords
[0][1] = -1.0f
; coords
[0][2] = 1.0f
;
4363 coords
[1][0] = 1.0f
; coords
[1][1] = -1.0f
; coords
[1][2] = -1.0f
;
4364 coords
[2][0] = 1.0f
; coords
[2][1] = 1.0f
; coords
[2][2] = 1.0f
;
4365 coords
[3][0] = 1.0f
; coords
[3][1] = 1.0f
; coords
[3][2] = -1.0f
;
4367 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
4368 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4369 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4370 info
->tex_type
= tex_cube
;
4371 coords
[0][0] = -1.0f
; coords
[0][1] = -1.0f
; coords
[0][2] = -1.0f
;
4372 coords
[1][0] = -1.0f
; coords
[1][1] = -1.0f
; coords
[1][2] = 1.0f
;
4373 coords
[2][0] = -1.0f
; coords
[2][1] = 1.0f
; coords
[2][2] = -1.0f
;
4374 coords
[3][0] = -1.0f
; coords
[3][1] = 1.0f
; coords
[3][2] = 1.0f
;
4376 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
4377 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4378 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4379 info
->tex_type
= tex_cube
;
4380 coords
[0][0] = -1.0f
; coords
[0][1] = 1.0f
; coords
[0][2] = 1.0f
;
4381 coords
[1][0] = 1.0f
; coords
[1][1] = 1.0f
; coords
[1][2] = 1.0f
;
4382 coords
[2][0] = -1.0f
; coords
[2][1] = 1.0f
; coords
[2][2] = -1.0f
;
4383 coords
[3][0] = 1.0f
; coords
[3][1] = 1.0f
; coords
[3][2] = -1.0f
;
4385 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
4386 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4387 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4388 info
->tex_type
= tex_cube
;
4389 coords
[0][0] = -1.0f
; coords
[0][1] = -1.0f
; coords
[0][2] = -1.0f
;
4390 coords
[1][0] = 1.0f
; coords
[1][1] = -1.0f
; coords
[1][2] = -1.0f
;
4391 coords
[2][0] = -1.0f
; coords
[2][1] = -1.0f
; coords
[2][2] = 1.0f
;
4392 coords
[3][0] = 1.0f
; coords
[3][1] = -1.0f
; coords
[3][2] = 1.0f
;
4394 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
4395 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4396 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4397 info
->tex_type
= tex_cube
;
4398 coords
[0][0] = -1.0f
; coords
[0][1] = -1.0f
; coords
[0][2] = 1.0f
;
4399 coords
[1][0] = 1.0f
; coords
[1][1] = -1.0f
; coords
[1][2] = 1.0f
;
4400 coords
[2][0] = -1.0f
; coords
[2][1] = 1.0f
; coords
[2][2] = 1.0f
;
4401 coords
[3][0] = 1.0f
; coords
[3][1] = 1.0f
; coords
[3][2] = 1.0f
;
4403 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
4404 info
->binding
= GL_TEXTURE_BINDING_CUBE_MAP_ARB
;
4405 info
->bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4406 info
->tex_type
= tex_cube
;
4407 coords
[0][0] = 1.0f
; coords
[0][1] = -1.0f
; coords
[0][2] = -1.0f
;
4408 coords
[1][0] = -1.0f
; coords
[1][1] = -1.0f
; coords
[1][2] = -1.0f
;
4409 coords
[2][0] = 1.0f
; coords
[2][1] = 1.0f
; coords
[2][2] = -1.0f
;
4410 coords
[3][0] = -1.0f
; coords
[3][1] = 1.0f
; coords
[3][2] = -1.0f
;
4414 /* GL locking is done by the caller */
4415 static void surface_depth_blt(IWineD3DSurfaceImpl
*This
, GLuint texture
, GLsizei w
, GLsizei h
, GLenum target
)
4417 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
4418 struct depth_blt_info info
;
4419 GLint old_binding
= 0;
4421 glPushAttrib(GL_ENABLE_BIT
| GL_DEPTH_BUFFER_BIT
| GL_COLOR_BUFFER_BIT
| GL_VIEWPORT_BIT
);
4423 glDisable(GL_CULL_FACE
);
4424 glDisable(GL_BLEND
);
4425 glDisable(GL_ALPHA_TEST
);
4426 glDisable(GL_SCISSOR_TEST
);
4427 glDisable(GL_STENCIL_TEST
);
4428 glEnable(GL_DEPTH_TEST
);
4429 glDepthFunc(GL_ALWAYS
);
4430 glDepthMask(GL_TRUE
);
4431 glColorMask(GL_FALSE
, GL_FALSE
, GL_FALSE
, GL_FALSE
);
4432 glViewport(0, 0, w
, h
);
4434 surface_get_depth_blt_info(target
, w
, h
, &info
);
4435 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB
));
4436 glGetIntegerv(info
.binding
, &old_binding
);
4437 glBindTexture(info
.bind_target
, texture
);
4439 device
->shader_backend
->shader_select_depth_blt((IWineD3DDevice
*)device
, info
.tex_type
);
4441 glBegin(GL_TRIANGLE_STRIP
);
4442 glTexCoord3fv(info
.coords
[0]);
4443 glVertex2f(-1.0f
, -1.0f
);
4444 glTexCoord3fv(info
.coords
[1]);
4445 glVertex2f(1.0f
, -1.0f
);
4446 glTexCoord3fv(info
.coords
[2]);
4447 glVertex2f(-1.0f
, 1.0f
);
4448 glTexCoord3fv(info
.coords
[3]);
4449 glVertex2f(1.0f
, 1.0f
);
4452 glBindTexture(info
.bind_target
, old_binding
);
4456 device
->shader_backend
->shader_deselect_depth_blt((IWineD3DDevice
*)device
);
4459 void surface_modify_ds_location(IWineD3DSurface
*iface
, DWORD location
) {
4460 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
4462 TRACE("(%p) New location %#x\n", This
, location
);
4464 if (location
& ~SFLAG_DS_LOCATIONS
) {
4465 FIXME("(%p) Invalid location (%#x) specified\n", This
, location
);
4468 This
->Flags
&= ~SFLAG_DS_LOCATIONS
;
4469 This
->Flags
|= location
;
4472 /* Context activation is done by the caller. */
4473 void surface_load_ds_location(IWineD3DSurface
*iface
, struct wined3d_context
*context
, DWORD location
)
4475 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*)iface
;
4476 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
4477 const struct wined3d_gl_info
*gl_info
= context
->gl_info
;
4479 TRACE("(%p) New location %#x\n", This
, location
);
4481 /* TODO: Make this work for modes other than FBO */
4482 if (wined3d_settings
.offscreen_rendering_mode
!= ORM_FBO
) return;
4484 if (This
->Flags
& location
) {
4485 TRACE("(%p) Location (%#x) is already up to date\n", This
, location
);
4489 if (This
->current_renderbuffer
) {
4490 FIXME("(%p) Not supported with fixed up depth stencil\n", This
);
4494 if (location
== SFLAG_DS_OFFSCREEN
) {
4495 if (This
->Flags
& SFLAG_DS_ONSCREEN
) {
4496 GLint old_binding
= 0;
4499 TRACE("(%p) Copying onscreen depth buffer to depth texture\n", This
);
4503 if (!device
->depth_blt_texture
) {
4504 glGenTextures(1, &device
->depth_blt_texture
);
4507 /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4508 * directly on the FBO texture. That's because we need to flip. */
4509 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
4510 if (This
->texture_target
== GL_TEXTURE_RECTANGLE_ARB
)
4512 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB
, &old_binding
);
4513 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4515 glGetIntegerv(GL_TEXTURE_BINDING_2D
, &old_binding
);
4516 bind_target
= GL_TEXTURE_2D
;
4518 glBindTexture(bind_target
, device
->depth_blt_texture
);
4519 glCopyTexImage2D(bind_target
, This
->texture_level
, This
->resource
.format_desc
->glInternal
,
4520 0, 0, This
->currentDesc
.Width
, This
->currentDesc
.Height
, 0);
4521 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4522 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4523 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_S
, GL_CLAMP_TO_EDGE
);
4524 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_T
, GL_CLAMP_TO_EDGE
);
4525 glTexParameteri(bind_target
, GL_TEXTURE_WRAP_R
, GL_CLAMP_TO_EDGE
);
4526 glTexParameteri(bind_target
, GL_DEPTH_TEXTURE_MODE_ARB
, GL_LUMINANCE
);
4527 glBindTexture(bind_target
, old_binding
);
4529 /* Setup the destination */
4530 if (!device
->depth_blt_rb
) {
4531 gl_info
->fbo_ops
.glGenRenderbuffers(1, &device
->depth_blt_rb
);
4532 checkGLcall("glGenRenderbuffersEXT");
4534 if (device
->depth_blt_rb_w
!= This
->currentDesc
.Width
4535 || device
->depth_blt_rb_h
!= This
->currentDesc
.Height
) {
4536 gl_info
->fbo_ops
.glBindRenderbuffer(GL_RENDERBUFFER
, device
->depth_blt_rb
);
4537 checkGLcall("glBindRenderbufferEXT");
4538 gl_info
->fbo_ops
.glRenderbufferStorage(GL_RENDERBUFFER
, GL_RGBA8
,
4539 This
->currentDesc
.Width
, This
->currentDesc
.Height
);
4540 checkGLcall("glRenderbufferStorageEXT");
4541 device
->depth_blt_rb_w
= This
->currentDesc
.Width
;
4542 device
->depth_blt_rb_h
= This
->currentDesc
.Height
;
4545 context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->dst_fbo
);
4546 gl_info
->fbo_ops
.glFramebufferRenderbuffer(GL_FRAMEBUFFER
,
4547 GL_COLOR_ATTACHMENT0
, GL_RENDERBUFFER
, device
->depth_blt_rb
);
4548 checkGLcall("glFramebufferRenderbufferEXT");
4549 context_attach_depth_stencil_fbo(context
, GL_FRAMEBUFFER
, iface
, FALSE
);
4551 /* Do the actual blit */
4552 surface_depth_blt(This
, device
->depth_blt_texture
, This
->currentDesc
.Width
, This
->currentDesc
.Height
, bind_target
);
4553 checkGLcall("depth_blt");
4555 if (context
->current_fbo
) context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->current_fbo
->id
);
4556 else context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
4560 FIXME("No up to date depth stencil location\n");
4562 } else if (location
== SFLAG_DS_ONSCREEN
) {
4563 if (This
->Flags
& SFLAG_DS_OFFSCREEN
) {
4564 TRACE("(%p) Copying depth texture to onscreen depth buffer\n", This
);
4568 context_bind_fbo(context
, GL_FRAMEBUFFER
, NULL
);
4569 surface_depth_blt(This
, This
->texture_name
, This
->currentDesc
.Width
,
4570 This
->currentDesc
.Height
, This
->texture_target
);
4571 checkGLcall("depth_blt");
4573 if (context
->current_fbo
) context_bind_fbo(context
, GL_FRAMEBUFFER
, &context
->current_fbo
->id
);
4577 FIXME("No up to date depth stencil location\n");
4580 ERR("(%p) Invalid location (%#x) specified\n", This
, location
);
4583 This
->Flags
|= location
;
4586 static void WINAPI
IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface
*iface
, DWORD flag
, BOOL persistent
) {
4587 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
4588 IWineD3DBaseTexture
*texture
;
4589 IWineD3DSurfaceImpl
*overlay
;
4591 TRACE("(%p)->(%s, %s)\n", iface
, debug_surflocation(flag
),
4592 persistent
? "TRUE" : "FALSE");
4594 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4595 if (surface_is_offscreen(iface
))
4597 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4598 if (flag
& (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
)) flag
|= (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
);
4602 TRACE("Surface %p is an onscreen surface\n", iface
);
4607 if(((This
->Flags
& SFLAG_INTEXTURE
) && !(flag
& SFLAG_INTEXTURE
)) ||
4608 ((This
->Flags
& SFLAG_INSRGBTEX
) && !(flag
& SFLAG_INSRGBTEX
))) {
4609 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&texture
) == WINED3D_OK
) {
4610 TRACE("Passing to container\n");
4611 IWineD3DBaseTexture_SetDirty(texture
, TRUE
);
4612 IWineD3DBaseTexture_Release(texture
);
4615 This
->Flags
&= ~SFLAG_LOCATIONS
;
4616 This
->Flags
|= flag
;
4618 /* Redraw emulated overlays, if any */
4619 if(flag
& SFLAG_INDRAWABLE
&& !list_empty(&This
->overlays
)) {
4620 LIST_FOR_EACH_ENTRY(overlay
, &This
->overlays
, IWineD3DSurfaceImpl
, overlay_entry
) {
4621 IWineD3DSurface_DrawOverlay((IWineD3DSurface
*) overlay
);
4625 if((This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
)) && (flag
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))) {
4626 if (IWineD3DSurface_GetContainer(iface
, &IID_IWineD3DBaseTexture
, (void **)&texture
) == WINED3D_OK
) {
4627 TRACE("Passing to container\n");
4628 IWineD3DBaseTexture_SetDirty(texture
, TRUE
);
4629 IWineD3DBaseTexture_Release(texture
);
4632 This
->Flags
&= ~flag
;
4635 if(!(This
->Flags
& SFLAG_LOCATIONS
)) {
4636 ERR("%p: Surface does not have any up to date location\n", This
);
4652 static inline void cube_coords_float(const RECT
*r
, UINT w
, UINT h
, struct float_rect
*f
)
4654 f
->l
= ((r
->left
* 2.0f
) / w
) - 1.0f
;
4655 f
->t
= ((r
->top
* 2.0f
) / h
) - 1.0f
;
4656 f
->r
= ((r
->right
* 2.0f
) / w
) - 1.0f
;
4657 f
->b
= ((r
->bottom
* 2.0f
) / h
) - 1.0f
;
4660 static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl
*This
, const RECT
*rect_in
)
4662 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
4663 struct wined3d_context
*context
;
4664 struct coords coords
[4];
4666 IWineD3DSwapChain
*swapchain
;
4667 IWineD3DBaseTexture
*texture
;
4669 struct float_rect f
;
4676 rect
.right
= This
->currentDesc
.Width
;
4677 rect
.bottom
= This
->currentDesc
.Height
;
4680 switch (This
->texture_target
)
4683 bind_target
= GL_TEXTURE_2D
;
4685 coords
[0].x
= (float)rect
.left
/ This
->pow2Width
;
4686 coords
[0].y
= (float)rect
.top
/ This
->pow2Height
;
4689 coords
[1].x
= (float)rect
.left
/ This
->pow2Width
;
4690 coords
[1].y
= (float)rect
.bottom
/ This
->pow2Height
;
4693 coords
[2].x
= (float)rect
.right
/ This
->pow2Width
;
4694 coords
[2].y
= (float)rect
.bottom
/ This
->pow2Height
;
4697 coords
[3].x
= (float)rect
.right
/ This
->pow2Width
;
4698 coords
[3].y
= (float)rect
.top
/ This
->pow2Height
;
4702 case GL_TEXTURE_RECTANGLE_ARB
:
4703 bind_target
= GL_TEXTURE_RECTANGLE_ARB
;
4704 coords
[0].x
= rect
.left
; coords
[0].y
= rect
.top
; coords
[0].z
= 0;
4705 coords
[1].x
= rect
.left
; coords
[1].y
= rect
.bottom
; coords
[1].z
= 0;
4706 coords
[2].x
= rect
.right
; coords
[2].y
= rect
.bottom
; coords
[2].z
= 0;
4707 coords
[3].x
= rect
.right
; coords
[3].y
= rect
.top
; coords
[3].z
= 0;
4710 case GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
4711 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4712 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4713 coords
[0].x
= 1; coords
[0].y
= -f
.t
; coords
[0].z
= -f
.l
;
4714 coords
[1].x
= 1; coords
[1].y
= -f
.b
; coords
[1].z
= -f
.l
;
4715 coords
[2].x
= 1; coords
[2].y
= -f
.b
; coords
[2].z
= -f
.r
;
4716 coords
[3].x
= 1; coords
[3].y
= -f
.t
; coords
[3].z
= -f
.r
;
4719 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
4720 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4721 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4722 coords
[0].x
= -1; coords
[0].y
= -f
.t
; coords
[0].z
= f
.l
;
4723 coords
[1].x
= -1; coords
[1].y
= -f
.b
; coords
[1].z
= f
.l
;
4724 coords
[2].x
= -1; coords
[2].y
= -f
.b
; coords
[2].z
= f
.r
;
4725 coords
[3].x
= -1; coords
[3].y
= -f
.t
; coords
[3].z
= f
.r
;
4728 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
4729 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4730 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4731 coords
[0].x
= f
.l
; coords
[0].y
= 1; coords
[0].z
= f
.t
;
4732 coords
[1].x
= f
.l
; coords
[1].y
= 1; coords
[1].z
= f
.b
;
4733 coords
[2].x
= f
.r
; coords
[2].y
= 1; coords
[2].z
= f
.b
;
4734 coords
[3].x
= f
.r
; coords
[3].y
= 1; coords
[3].z
= f
.t
;
4737 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
4738 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4739 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4740 coords
[0].x
= f
.l
; coords
[0].y
= -1; coords
[0].z
= -f
.t
;
4741 coords
[1].x
= f
.l
; coords
[1].y
= -1; coords
[1].z
= -f
.b
;
4742 coords
[2].x
= f
.r
; coords
[2].y
= -1; coords
[2].z
= -f
.b
;
4743 coords
[3].x
= f
.r
; coords
[3].y
= -1; coords
[3].z
= -f
.t
;
4746 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
4747 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4748 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4749 coords
[0].x
= f
.l
; coords
[0].y
= -f
.t
; coords
[0].z
= 1;
4750 coords
[1].x
= f
.l
; coords
[1].y
= -f
.b
; coords
[1].z
= 1;
4751 coords
[2].x
= f
.r
; coords
[2].y
= -f
.b
; coords
[2].z
= 1;
4752 coords
[3].x
= f
.r
; coords
[3].y
= -f
.t
; coords
[3].z
= 1;
4755 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
4756 bind_target
= GL_TEXTURE_CUBE_MAP_ARB
;
4757 cube_coords_float(&rect
, This
->pow2Width
, This
->pow2Height
, &f
);
4758 coords
[0].x
= -f
.l
; coords
[0].y
= -f
.t
; coords
[0].z
= -1;
4759 coords
[1].x
= -f
.l
; coords
[1].y
= -f
.b
; coords
[1].z
= -1;
4760 coords
[2].x
= -f
.r
; coords
[2].y
= -f
.b
; coords
[2].z
= -1;
4761 coords
[3].x
= -f
.r
; coords
[3].y
= -f
.t
; coords
[3].z
= -1;
4765 ERR("Unexpected texture target %#x\n", This
->texture_target
);
4769 context
= context_acquire(device
, (IWineD3DSurface
*)This
, CTXUSAGE_BLIT
);
4773 glEnable(bind_target
);
4774 checkGLcall("glEnable(bind_target)");
4775 glBindTexture(bind_target
, This
->texture_name
);
4776 checkGLcall("glBindTexture(bind_target, This->texture_name)");
4777 glTexParameteri(bind_target
, GL_TEXTURE_MAG_FILTER
, GL_NEAREST
);
4778 checkGLcall("glTexParameteri");
4779 glTexParameteri(bind_target
, GL_TEXTURE_MIN_FILTER
, GL_NEAREST
);
4780 checkGLcall("glTexParameteri");
4782 if (context
->render_offscreen
)
4784 LONG tmp
= rect
.top
;
4785 rect
.top
= rect
.bottom
;
4790 glTexCoord3fv(&coords
[0].x
);
4791 glVertex2i(rect
.left
, rect
.top
);
4793 glTexCoord3fv(&coords
[1].x
);
4794 glVertex2i(rect
.left
, rect
.bottom
);
4796 glTexCoord3fv(&coords
[2].x
);
4797 glVertex2i(rect
.right
, rect
.bottom
);
4799 glTexCoord3fv(&coords
[3].x
);
4800 glVertex2i(rect
.right
, rect
.top
);
4802 checkGLcall("glEnd");
4804 glDisable(bind_target
);
4805 checkGLcall("glDisable(bind_target)");
4809 if(SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)This
, &IID_IWineD3DSwapChain
, (void **) &swapchain
)))
4811 /* Make sure to flush the buffers. This is needed in apps like Red Alert II and Tiberian SUN that use multiple WGL contexts. */
4812 if(((IWineD3DSwapChainImpl
*)swapchain
)->frontBuffer
== (IWineD3DSurface
*)This
||
4813 ((IWineD3DSwapChainImpl
*)swapchain
)->num_contexts
>= 2)
4816 IWineD3DSwapChain_Release(swapchain
);
4818 /* We changed the filtering settings on the texture. Inform the container about this to get the filters
4819 * reset properly next draw
4821 if(SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface
*)This
, &IID_IWineD3DBaseTexture
, (void **) &texture
)))
4823 ((IWineD3DBaseTextureImpl
*) texture
)->baseTexture
.texture_rgb
.states
[WINED3DTEXSTA_MAGFILTER
] = WINED3DTEXF_POINT
;
4824 ((IWineD3DBaseTextureImpl
*) texture
)->baseTexture
.texture_rgb
.states
[WINED3DTEXSTA_MINFILTER
] = WINED3DTEXF_POINT
;
4825 ((IWineD3DBaseTextureImpl
*) texture
)->baseTexture
.texture_rgb
.states
[WINED3DTEXSTA_MIPFILTER
] = WINED3DTEXF_NONE
;
4826 IWineD3DBaseTexture_Release(texture
);
4830 context_release(context
);
4833 /*****************************************************************************
4834 * IWineD3DSurface::LoadLocation
4836 * Copies the current surface data from wherever it is to the requested
4837 * location. The location is one of the surface flags, SFLAG_INSYSMEM,
4838 * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
4839 * multiple locations, the gl texture is preferred over the drawable, which is
4840 * preferred over system memory. The PBO counts as system memory. If rect is
4841 * not NULL, only the specified rectangle is copied (only supported for
4842 * sysmem<->drawable copies at the moment). If rect is NULL, the destination
4843 * location is marked up to date after the copy.
4846 * flag: Surface location flag to be updated
4847 * rect: rectangle to be copied
4850 * WINED3D_OK on success
4851 * WINED3DERR_DEVICELOST on an internal error
4853 *****************************************************************************/
4854 static HRESULT WINAPI
IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface
*iface
, DWORD flag
, const RECT
*rect
) {
4855 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
4856 IWineD3DDeviceImpl
*device
= This
->resource
.device
;
4857 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
4858 GLenum format
, internal
, type
;
4859 CONVERT_TYPES convert
;
4861 int width
, pitch
, outpitch
;
4863 BOOL drawable_read_ok
= TRUE
;
4864 BOOL in_fbo
= FALSE
;
4866 if (wined3d_settings
.offscreen_rendering_mode
== ORM_FBO
) {
4867 if (surface_is_offscreen(iface
))
4869 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4870 * Prefer SFLAG_INTEXTURE. */
4871 if (flag
== SFLAG_INDRAWABLE
) flag
= SFLAG_INTEXTURE
;
4872 drawable_read_ok
= FALSE
;
4877 TRACE("Surface %p is an onscreen surface\n", iface
);
4881 TRACE("(%p)->(%s, %p)\n", iface
, debug_surflocation(flag
), rect
);
4883 TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
4886 if(This
->Flags
& flag
) {
4887 TRACE("Location already up to date\n");
4891 if(!(This
->Flags
& SFLAG_LOCATIONS
)) {
4892 ERR("%p: Surface does not have any up to date location\n", This
);
4893 This
->Flags
|= SFLAG_LOST
;
4894 return WINED3DERR_DEVICELOST
;
4897 if(flag
== SFLAG_INSYSMEM
) {
4898 surface_prepare_system_memory(This
);
4900 /* Download the surface to system memory */
4901 if (This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INSRGBTEX
))
4903 struct wined3d_context
*context
= NULL
;
4905 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
4907 surface_bind_and_dirtify(This
, !(This
->Flags
& SFLAG_INTEXTURE
));
4908 surface_download_data(This
);
4910 if (context
) context_release(context
);
4914 /* Note: It might be faster to download into a texture first. */
4915 read_from_framebuffer(This
, rect
,
4916 This
->resource
.allocatedMemory
,
4917 IWineD3DSurface_GetPitch(iface
));
4919 } else if(flag
== SFLAG_INDRAWABLE
) {
4920 if(This
->Flags
& SFLAG_INTEXTURE
) {
4921 surface_blt_to_drawable(This
, rect
);
4923 if((This
->Flags
& SFLAG_LOCATIONS
) == SFLAG_INSRGBTEX
) {
4924 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4925 * values, otherwise we get incorrect values in the target. For now go the slow way
4926 * via a system memory copy
4928 IWineD3DSurfaceImpl_LoadLocation(iface
, SFLAG_INSYSMEM
, rect
);
4931 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, FALSE
/* We won't use textures */, &format
, &internal
, &type
, &convert
, &bpp
, FALSE
);
4933 /* The width is in 'length' not in bytes */
4934 width
= This
->currentDesc
.Width
;
4935 pitch
= IWineD3DSurface_GetPitch(iface
);
4937 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4938 * but it isn't set (yet) in all cases it is getting called. */
4939 if ((convert
!= NO_CONVERSION
) && (This
->Flags
& SFLAG_PBO
))
4941 struct wined3d_context
*context
= NULL
;
4943 TRACE("Removing the pbo attached to surface %p\n", This
);
4945 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
4946 surface_remove_pbo(This
);
4947 if (context
) context_release(context
);
4950 if((convert
!= NO_CONVERSION
) && This
->resource
.allocatedMemory
) {
4951 int height
= This
->currentDesc
.Height
;
4953 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4954 outpitch
= width
* bpp
;
4955 outpitch
= (outpitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
4957 mem
= HeapAlloc(GetProcessHeap(), 0, outpitch
* height
);
4959 ERR("Out of memory %d, %d!\n", outpitch
, height
);
4960 return WINED3DERR_OUTOFVIDEOMEMORY
;
4962 d3dfmt_convert_surface(This
->resource
.allocatedMemory
, mem
, pitch
, width
, height
, outpitch
, convert
, This
);
4964 This
->Flags
|= SFLAG_CONVERTED
;
4966 This
->Flags
&= ~SFLAG_CONVERTED
;
4967 mem
= This
->resource
.allocatedMemory
;
4970 flush_to_framebuffer_drawpixels(This
, format
, type
, bpp
, mem
);
4972 /* Don't delete PBO memory */
4973 if((mem
!= This
->resource
.allocatedMemory
) && !(This
->Flags
& SFLAG_PBO
))
4974 HeapFree(GetProcessHeap(), 0, mem
);
4976 } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
4977 if (drawable_read_ok
&& (This
->Flags
& SFLAG_INDRAWABLE
)) {
4978 read_from_framebuffer_texture(This
, flag
== SFLAG_INSRGBTEX
);
4982 /* Upload from system memory */
4983 BOOL srgb
= flag
== SFLAG_INSRGBTEX
;
4984 DWORD alloc_flag
= srgb
? SFLAG_SRGBALLOCATED
: SFLAG_ALLOCATED
;
4985 struct wined3d_context
*context
= NULL
;
4987 d3dfmt_get_conv(This
, TRUE
/* We need color keying */, TRUE
/* We will use textures */,
4988 &format
, &internal
, &type
, &convert
, &bpp
, srgb
);
4991 if((This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INSYSMEM
)) == SFLAG_INTEXTURE
) {
4992 /* Performance warning ... */
4993 FIXME("%p: Downloading rgb texture to reload it as srgb\n", This
);
4994 IWineD3DSurfaceImpl_LoadLocation(iface
, SFLAG_INSYSMEM
, rect
);
4997 if((This
->Flags
& (SFLAG_INSRGBTEX
| SFLAG_INSYSMEM
)) == SFLAG_INSRGBTEX
) {
4998 /* Performance warning ... */
4999 FIXME("%p: Downloading srgb texture to reload it as rgb\n", This
);
5000 IWineD3DSurfaceImpl_LoadLocation(iface
, SFLAG_INSYSMEM
, rect
);
5003 if(!(This
->Flags
& SFLAG_INSYSMEM
)) {
5004 /* Should not happen */
5005 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
5006 /* Lets hope we get it from somewhere... */
5007 IWineD3DSurfaceImpl_LoadLocation(iface
, SFLAG_INSYSMEM
, rect
);
5010 if (!device
->isInDraw
) context
= context_acquire(device
, NULL
, CTXUSAGE_RESOURCELOAD
);
5011 surface_bind_and_dirtify(This
, srgb
);
5013 if(This
->CKeyFlags
& WINEDDSD_CKSRCBLT
) {
5014 This
->Flags
|= SFLAG_GLCKEY
;
5015 This
->glCKey
= This
->SrcBltCKey
;
5017 else This
->Flags
&= ~SFLAG_GLCKEY
;
5019 /* The width is in 'length' not in bytes */
5020 width
= This
->currentDesc
.Width
;
5021 pitch
= IWineD3DSurface_GetPitch(iface
);
5023 /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
5024 * but it isn't set (yet) in all cases it is getting called. */
5025 if((convert
!= NO_CONVERSION
) && (This
->Flags
& SFLAG_PBO
)) {
5026 TRACE("Removing the pbo attached to surface %p\n", This
);
5027 surface_remove_pbo(This
);
5030 if((convert
!= NO_CONVERSION
) && This
->resource
.allocatedMemory
) {
5031 int height
= This
->currentDesc
.Height
;
5033 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
5034 outpitch
= width
* bpp
;
5035 outpitch
= (outpitch
+ device
->surface_alignment
- 1) & ~(device
->surface_alignment
- 1);
5037 mem
= HeapAlloc(GetProcessHeap(), 0, outpitch
* height
);
5039 ERR("Out of memory %d, %d!\n", outpitch
, height
);
5040 if (context
) context_release(context
);
5041 return WINED3DERR_OUTOFVIDEOMEMORY
;
5043 d3dfmt_convert_surface(This
->resource
.allocatedMemory
, mem
, pitch
, width
, height
, outpitch
, convert
, This
);
5045 This
->Flags
|= SFLAG_CONVERTED
;
5047 else if (This
->resource
.format_desc
->format
== WINED3DFMT_P8_UINT
5048 && (gl_info
->supported
[EXT_PALETTED_TEXTURE
] || gl_info
->supported
[ARB_FRAGMENT_PROGRAM
]))
5050 d3dfmt_p8_upload_palette(iface
, convert
);
5051 This
->Flags
&= ~SFLAG_CONVERTED
;
5052 mem
= This
->resource
.allocatedMemory
;
5054 This
->Flags
&= ~SFLAG_CONVERTED
;
5055 mem
= This
->resource
.allocatedMemory
;
5058 /* Make sure the correct pitch is used */
5060 glPixelStorei(GL_UNPACK_ROW_LENGTH
, width
);
5063 if ((This
->Flags
& SFLAG_NONPOW2
) && !(This
->Flags
& SFLAG_OVERSIZE
)) {
5064 TRACE("non power of two support\n");
5065 if(!(This
->Flags
& alloc_flag
)) {
5066 surface_allocate_surface(This
, internal
, This
->pow2Width
, This
->pow2Height
, format
, type
);
5067 This
->Flags
|= alloc_flag
;
5069 if (mem
|| (This
->Flags
& SFLAG_PBO
)) {
5070 surface_upload_data(This
, internal
, This
->currentDesc
.Width
, This
->currentDesc
.Height
, format
, type
, mem
);
5073 /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
5074 * changed. So also keep track of memory changes. In this case the texture has to be reallocated
5076 if(!(This
->Flags
& alloc_flag
)) {
5077 surface_allocate_surface(This
, internal
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
);
5078 This
->Flags
|= alloc_flag
;
5080 if (mem
|| (This
->Flags
& SFLAG_PBO
)) {
5081 surface_upload_data(This
, internal
, This
->glRect
.right
- This
->glRect
.left
, This
->glRect
.bottom
- This
->glRect
.top
, format
, type
, mem
);
5085 /* Restore the default pitch */
5087 glPixelStorei(GL_UNPACK_ROW_LENGTH
, 0);
5090 if (context
) context_release(context
);
5092 /* Don't delete PBO memory */
5093 if((mem
!= This
->resource
.allocatedMemory
) && !(This
->Flags
& SFLAG_PBO
))
5094 HeapFree(GetProcessHeap(), 0, mem
);
5099 This
->Flags
|= flag
;
5102 if (in_fbo
&& (This
->Flags
& (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
))) {
5103 /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
5104 This
->Flags
|= (SFLAG_INTEXTURE
| SFLAG_INDRAWABLE
);
5110 static HRESULT WINAPI
IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface
*iface
, IWineD3DBase
*container
)
5112 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
5113 IWineD3DSwapChain
*swapchain
= NULL
;
5115 /* Update the drawable size method */
5117 IWineD3DBase_QueryInterface(container
, &IID_IWineD3DSwapChain
, (void **) &swapchain
);
5120 This
->get_drawable_size
= get_drawable_size_swapchain
;
5121 IWineD3DSwapChain_Release(swapchain
);
5122 } else if(This
->resource
.usage
& WINED3DUSAGE_RENDERTARGET
) {
5123 switch(wined3d_settings
.offscreen_rendering_mode
) {
5124 case ORM_FBO
: This
->get_drawable_size
= get_drawable_size_fbo
; break;
5125 case ORM_PBUFFER
: This
->get_drawable_size
= get_drawable_size_pbuffer
; break;
5126 case ORM_BACKBUFFER
: This
->get_drawable_size
= get_drawable_size_backbuffer
; break;
5130 return IWineD3DBaseSurfaceImpl_SetContainer(iface
, container
);
5133 static WINED3DSURFTYPE WINAPI
IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface
*iface
) {
5134 return SURFACE_OPENGL
;
5137 static HRESULT WINAPI
IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface
*iface
) {
5138 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
5141 /* If there's no destination surface there is nothing to do */
5142 if(!This
->overlay_dest
) return WINED3D_OK
;
5144 /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
5145 * update the overlay. Prevent an endless recursion
5147 if(This
->overlay_dest
->Flags
& SFLAG_INOVERLAYDRAW
) {
5150 This
->overlay_dest
->Flags
|= SFLAG_INOVERLAYDRAW
;
5151 hr
= IWineD3DSurfaceImpl_Blt((IWineD3DSurface
*) This
->overlay_dest
, &This
->overlay_destrect
,
5152 iface
, &This
->overlay_srcrect
, WINEDDBLT_WAIT
,
5153 NULL
, WINED3DTEXF_LINEAR
);
5154 This
->overlay_dest
->Flags
&= ~SFLAG_INOVERLAYDRAW
;
5159 BOOL
surface_is_offscreen(IWineD3DSurface
*iface
)
5161 IWineD3DSurfaceImpl
*This
= (IWineD3DSurfaceImpl
*) iface
;
5162 IWineD3DSwapChainImpl
*swapchain
= (IWineD3DSwapChainImpl
*) This
->container
;
5164 /* Not on a swapchain - must be offscreen */
5165 if (!(This
->Flags
& SFLAG_SWAPCHAIN
)) return TRUE
;
5167 /* The front buffer is always onscreen */
5168 if(iface
== swapchain
->frontBuffer
) return FALSE
;
5170 /* If the swapchain is rendered to an FBO, the backbuffer is
5171 * offscreen, otherwise onscreen */
5172 return swapchain
->render_to_fbo
;
5175 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl
=
5178 IWineD3DBaseSurfaceImpl_QueryInterface
,
5179 IWineD3DBaseSurfaceImpl_AddRef
,
5180 IWineD3DSurfaceImpl_Release
,
5181 /* IWineD3DResource */
5182 IWineD3DBaseSurfaceImpl_GetParent
,
5183 IWineD3DBaseSurfaceImpl_SetPrivateData
,
5184 IWineD3DBaseSurfaceImpl_GetPrivateData
,
5185 IWineD3DBaseSurfaceImpl_FreePrivateData
,
5186 IWineD3DBaseSurfaceImpl_SetPriority
,
5187 IWineD3DBaseSurfaceImpl_GetPriority
,
5188 IWineD3DSurfaceImpl_PreLoad
,
5189 IWineD3DSurfaceImpl_UnLoad
,
5190 IWineD3DBaseSurfaceImpl_GetType
,
5191 /* IWineD3DSurface */
5192 IWineD3DBaseSurfaceImpl_GetContainer
,
5193 IWineD3DBaseSurfaceImpl_GetDesc
,
5194 IWineD3DSurfaceImpl_LockRect
,
5195 IWineD3DSurfaceImpl_UnlockRect
,
5196 IWineD3DSurfaceImpl_GetDC
,
5197 IWineD3DSurfaceImpl_ReleaseDC
,
5198 IWineD3DSurfaceImpl_Flip
,
5199 IWineD3DSurfaceImpl_Blt
,
5200 IWineD3DBaseSurfaceImpl_GetBltStatus
,
5201 IWineD3DBaseSurfaceImpl_GetFlipStatus
,
5202 IWineD3DBaseSurfaceImpl_IsLost
,
5203 IWineD3DBaseSurfaceImpl_Restore
,
5204 IWineD3DSurfaceImpl_BltFast
,
5205 IWineD3DBaseSurfaceImpl_GetPalette
,
5206 IWineD3DBaseSurfaceImpl_SetPalette
,
5207 IWineD3DSurfaceImpl_RealizePalette
,
5208 IWineD3DBaseSurfaceImpl_SetColorKey
,
5209 IWineD3DBaseSurfaceImpl_GetPitch
,
5210 IWineD3DSurfaceImpl_SetMem
,
5211 IWineD3DBaseSurfaceImpl_SetOverlayPosition
,
5212 IWineD3DBaseSurfaceImpl_GetOverlayPosition
,
5213 IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder
,
5214 IWineD3DBaseSurfaceImpl_UpdateOverlay
,
5215 IWineD3DBaseSurfaceImpl_SetClipper
,
5216 IWineD3DBaseSurfaceImpl_GetClipper
,
5218 IWineD3DSurfaceImpl_LoadTexture
,
5219 IWineD3DSurfaceImpl_BindTexture
,
5220 IWineD3DSurfaceImpl_SaveSnapshot
,
5221 IWineD3DSurfaceImpl_SetContainer
,
5222 IWineD3DBaseSurfaceImpl_GetData
,
5223 IWineD3DSurfaceImpl_SetFormat
,
5224 IWineD3DSurfaceImpl_PrivateSetup
,
5225 IWineD3DSurfaceImpl_ModifyLocation
,
5226 IWineD3DSurfaceImpl_LoadLocation
,
5227 IWineD3DSurfaceImpl_GetImplType
,
5228 IWineD3DSurfaceImpl_DrawOverlay
5230 #undef GLINFO_LOCATION
5232 #define GLINFO_LOCATION device->adapter->gl_info
5233 static HRESULT
ffp_blit_alloc(IWineD3DDevice
*iface
) { return WINED3D_OK
; }
5234 /* Context activation is done by the caller. */
5235 static void ffp_blit_free(IWineD3DDevice
*iface
) { }
5237 /* Context activation is done by the caller. */
5238 static HRESULT
ffp_blit_set(IWineD3DDevice
*iface
, const struct GlPixelFormatDesc
*format_desc
,
5239 GLenum textype
, UINT width
, UINT height
)
5243 checkGLcall("glEnable(textype)");
5248 /* Context activation is done by the caller. */
5249 static void ffp_blit_unset(IWineD3DDevice
*iface
)
5251 IWineD3DDeviceImpl
*device
= (IWineD3DDeviceImpl
*) iface
;
5252 const struct wined3d_gl_info
*gl_info
= &device
->adapter
->gl_info
;
5255 glDisable(GL_TEXTURE_2D
);
5256 checkGLcall("glDisable(GL_TEXTURE_2D)");
5257 if (gl_info
->supported
[ARB_TEXTURE_CUBE_MAP
])
5259 glDisable(GL_TEXTURE_CUBE_MAP_ARB
);
5260 checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
5262 if (gl_info
->supported
[ARB_TEXTURE_RECTANGLE
])
5264 glDisable(GL_TEXTURE_RECTANGLE_ARB
);
5265 checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
5270 static BOOL
ffp_blit_color_fixup_supported(struct color_fixup_desc fixup
)
5272 if (TRACE_ON(d3d_surface
) && TRACE_ON(d3d
))
5274 TRACE("Checking support for fixup:\n");
5275 dump_color_fixup_desc(fixup
);
5278 /* We only support identity conversions. */
5279 if (is_identity_fixup(fixup
))
5285 TRACE("[FAILED]\n");
5289 const struct blit_shader ffp_blit
= {
5294 ffp_blit_color_fixup_supported