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 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
50 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
52 /* *******************************************
53 IWineD3DSurface IUnknown parts follow
54 ******************************************* */
55 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
57 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
58 /* Warn ,but be nice about things */
59 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
61 ERR("Probably FIXME: Calling query interface with NULL riid\n");
63 if (IsEqualGUID(riid, &IID_IUnknown)
64 || IsEqualGUID(riid, &IID_IWineD3DBase)
65 || IsEqualGUID(riid, &IID_IWineD3DResource)
66 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
67 IUnknown_AddRef((IUnknown*)iface);
75 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
76 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
77 ULONG ref = InterlockedIncrement(&This->resource.ref);
78 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
82 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
83 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
84 ULONG ref = InterlockedDecrement(&This->resource.ref);
85 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
87 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
88 TRACE("(%p) : cleaning up\n", This);
89 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
91 TRACE("Deleting texture %d\n", This->glDescription.textureName);
92 glDeleteTextures(1, &This->glDescription.textureName);
96 if(This->Flags & SFLAG_DIBSECTION) {
98 SelectObject(This->hDC, This->dib.holdbitmap);
100 /* Release the DIB section */
101 DeleteObject(This->dib.DIBsection);
102 This->dib.bitmap_data = NULL;
103 This->resource.allocatedMemory = NULL;
105 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
107 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
108 if(iface == device->ddraw_primary)
109 device->ddraw_primary = NULL;
111 TRACE("(%p) Released\n", This);
112 HeapFree(GetProcessHeap(), 0, This);
118 /* ****************************************************
119 IWineD3DSurface IWineD3DResource parts follow
120 **************************************************** */
121 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
125 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
129 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
133 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
137 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
141 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
145 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
146 /* TODO: re-write the way textures and managed,
147 * use a 'opengl context manager' to manage RenderTarget surfaces
148 ** *********************************************************/
150 /* TODO: check for locks */
151 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
152 IWineD3DBaseTexture *baseTexture = NULL;
153 TRACE("(%p)Checking to see if the container is a base texture\n", This);
154 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
155 TRACE("Passing to conatiner\n");
156 IWineD3DBaseTexture_PreLoad(baseTexture);
157 IWineD3DBaseTexture_Release(baseTexture);
159 TRACE("(%p) : About to load surface\n", This);
161 #if 0 /* TODO: context manager support */
162 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
164 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
165 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
166 glGenTextures(1, &This->glDescription.textureName);
167 checkGLcall("glGenTextures");
168 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
169 glBindTexture(This->glDescription.target, This->glDescription.textureName);
170 checkGLcall("glBindTexture");
171 IWineD3DSurface_LoadTexture(iface);
172 /* This is where we should be reducing the amount of GLMemoryUsed */
174 if (This->glDescription.level == 0) {
175 glBindTexture(This->glDescription.target, This->glDescription.textureName);
176 checkGLcall("glBindTexture");
177 IWineD3DSurface_LoadTexture(iface);
178 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
179 /* assume this is a coding error not a real error for now */
180 FIXME("Mipmap surface has a glTexture bound to it!\n");
183 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
184 /* Tell opengl to try and keep this texture in video ram (well mostly) */
187 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
189 /* TODO: disable texture support, if it wastn't enabled when we entered. */
190 #if 0 /* TODO: context manager support */
191 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
192 /* we don't care when the state is disabled(if atall) */);
199 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
200 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
201 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
204 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
205 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
206 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
209 /* ******************************************************
210 IWineD3DSurface IWineD3DSurface parts follow
211 ****************************************************** */
213 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
216 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
218 if (!ppContainerParent) {
219 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
222 if (This->container) {
223 IWineD3DBase_GetParent(This->container, ppContainerParent);
224 if (!ppContainerParent) {
225 /* WineD3D objects should always have a parent */
226 ERR("(%p) : GetParent returned NULL\n", This);
228 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
230 *ppContainerParent = NULL;
236 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
238 IWineD3DBase *container = 0;
240 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
243 ERR("Called without a valid ppContainer.\n");
247 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
248 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
249 * GetContainer will return the Direct3D device used to create the surface.
251 if (This->container) {
252 container = This->container;
254 container = (IWineD3DBase *)This->resource.wineD3DDevice;
257 TRACE("Relaying to QueryInterface\n");
258 return IUnknown_QueryInterface(container, riid, ppContainer);
261 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
262 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
264 TRACE("(%p) : copying into %p\n", This, pDesc);
265 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
266 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
267 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
268 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
269 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
270 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
271 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
272 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
273 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
277 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
278 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
279 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
280 if (This->glDescription.textureName == 0 && textureName != 0) {
281 This->Flags |= SFLAG_DIRTY;
282 IWineD3DSurface_AddDirtyRect(iface, NULL);
284 This->glDescription.textureName = textureName;
285 This->glDescription.target = target;
288 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
289 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
290 TRACE("(%p) : returning %p\n", This, &This->glDescription);
291 *glDescription = &This->glDescription;
294 /* TODO: think about moving this down to resource? */
295 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
296 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
297 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
298 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
299 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
301 return (CONST void*)(This->resource.allocatedMemory);
304 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
310 switch(This->resource.format)
314 /* GL can't return palettized data, so read ARGB pixels into a
315 * separate block of memory and convert them into palettized format
316 * in software. Slow, but if the app means to use palettized render
317 * targets and locks it...
319 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
320 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
321 * for the color channels when palettizing the colors.
324 type = GL_UNSIGNED_BYTE;
326 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
328 ERR("Out of memory\n");
336 fmt = This->glDescription.glFormat;
337 type = This->glDescription.glType;
340 if (rect->left == 0 &&
341 rect->right == This->currentDesc.Width ) {
342 BYTE *row, *top, *bottom;
345 glReadPixels(0, rect->top,
346 This->currentDesc.Width,
347 rect->bottom - rect->top,
352 /* glReadPixels returns the image upside down, and there is no way to prevent this.
353 Flip the lines in software */
354 row = HeapAlloc(GetProcessHeap(), 0, pitch);
356 ERR("Out of memory\n");
360 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
361 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
362 memcpy(row, top, pitch);
363 memcpy(top, bottom, pitch);
364 memcpy(bottom, row, pitch);
368 HeapFree(GetProcessHeap(), 0, row);
370 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
371 This->Flags &= ~SFLAG_GLDIRTY;
374 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
375 glReadPixels(rect->left,
376 rect->bottom - j - 1,
377 rect->right - rect->left,
381 (char *)mem + (pitch * (j-rect->top)));
385 vcheckGLcall("glReadPixels");
387 if(This->resource.format == WINED3DFMT_P8) {
389 DWORD width = pitch / 3;
392 pal = This->palette->palents;
394 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
397 for(y = rect->top; y < rect->bottom; y++) {
398 for(x = rect->left; x < rect->right; x++) {
399 /* start lines pixels */
400 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
401 BYTE *green = blue + 1;
402 BYTE *red = green + 1;
404 for(c = 0; c < 256; c++) {
405 if(*red == pal[c].peRed &&
406 *green == pal[c].peGreen &&
407 *blue == pal[c].peBlue)
409 *((BYTE *) dest + y * width + x) = c;
415 HeapFree(GetProcessHeap(), 0, mem);
419 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
420 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
421 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
422 IWineD3DSwapChainImpl *swapchain = NULL;
423 static UINT messages = 0; /* holds flags to disable fixme messages */
424 BOOL backbuf = FALSE;
426 /* fixme: should we really lock as such? */
427 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
428 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
429 FIXME("Warning: Surface is in texture memory or pbuffer\n");
430 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
433 if (!(This->Flags & SFLAG_LOCKABLE)) {
434 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
435 texture regions, and since the destination is an unlockable region we need
437 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
438 /*return WINED3DERR_INVALIDCALL; */
441 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
442 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
444 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
445 if(swapchain != NULL) {
447 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
448 if(iface == swapchain->backBuffer[i]) {
455 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
456 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
457 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
458 } else if (iface == myDevice->renderTarget) {
459 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
460 } else if (iface == myDevice->depthStencilBuffer) {
461 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
464 if (NULL != swapchain) {
465 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
470 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
473 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
476 pLockedRect->pBits = This->resource.allocatedMemory;
477 This->lockedRect.left = 0;
478 This->lockedRect.top = 0;
479 This->lockedRect.right = This->currentDesc.Width;
480 This->lockedRect.bottom = This->currentDesc.Height;
481 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
483 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
485 if ((pRect->top < 0) ||
487 (pRect->left >= pRect->right) ||
488 (pRect->top >= pRect->bottom) ||
489 (pRect->right > This->currentDesc.Width) ||
490 (pRect->bottom > This->currentDesc.Height))
492 WARN(" Invalid values in pRect !!!\n");
493 return D3DERR_INVALIDCALL;
496 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
497 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
499 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
501 This->lockedRect.left = pRect->left;
502 This->lockedRect.top = pRect->top;
503 This->lockedRect.right = pRect->right;
504 This->lockedRect.bottom = pRect->bottom;
507 if (This->Flags & SFLAG_NONPOW2) {
508 TRACE("Locking non-power 2 texture\n");
511 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
512 /* classic surface TODO: non 2d surfaces?
513 These resources may be POOL_SYSTEMMEM, so they must not access the device */
514 TRACE("locking an ordinarary surface\n");
515 /* Check to see if memory has already been allocated from the surface*/
516 if ((NULL == This->resource.allocatedMemory) ||
517 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
518 /* Non-system memory surfaces */
520 This->Flags &= ~SFLAG_GLDIRTY;
522 /*Surface has no memory currently allocated to it!*/
523 TRACE("(%p) Locking rect\n" , This);
524 if(!This->resource.allocatedMemory) {
525 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
527 if (0 != This->glDescription.textureName) {
528 /* Now I have to copy thing bits back */
529 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
530 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
533 /* Make sure that the texture is loaded */
534 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
536 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
538 if (This->resource.format == WINED3DFMT_DXT1 ||
539 This->resource.format == WINED3DFMT_DXT2 ||
540 This->resource.format == WINED3DFMT_DXT3 ||
541 This->resource.format == WINED3DFMT_DXT4 ||
542 This->resource.format == WINED3DFMT_DXT5) {
543 TRACE("Locking a compressed texture\n");
544 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
545 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
546 This->glDescription.level,
547 This->resource.allocatedMemory);
550 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
553 glGetTexImage(This->glDescription.target,
554 This->glDescription.level,
555 This->glDescription.glFormat,
556 This->glDescription.glType,
557 This->resource.allocatedMemory);
558 vcheckGLcall("glGetTexImage");
559 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
560 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
561 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
562 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
566 instead of boxing the texture :
567 |<-texture width ->| -->pow2width| /\
568 |111111111111111111| | |
569 |222 Texture 222222| boxed empty | texture height
570 |3333 Data 33333333| | |
571 |444444444444444444| | \/
572 ----------------------------------- |
573 | boxed empty | boxed empty | pow2height
575 -----------------------------------
578 were repacking the data to the expected texture width
580 |<-texture width ->| -->pow2width| /\
581 |111111111111111111222222222222222| |
582 |222333333333333333333444444444444| texture height
588 -----------------------------------
592 |<-texture width ->| /\
594 |222222222222222222|texture height
596 |444444444444444444| \/
599 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
601 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
603 if (This->Flags & SFLAG_NONPOW2) {
605 int pitcha = 0, pitchb = 0;
607 pitcha = This->bytesPerPixel * This->currentDesc.Width;
608 pitchb = This->bytesPerPixel * This->pow2Width;
609 datab = dataa = This->resource.allocatedMemory;
610 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
611 for (y = 1 ; y < This->currentDesc.Height; y++) {
612 dataa += pitcha; /* skip the first row */
614 memcpy(dataa, datab, pitcha);
621 } else { /* Nothing to do */
622 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
626 pLockedRect->pBits = This->resource.allocatedMemory;
628 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
629 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
631 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
635 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
636 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
639 BOOL notInContext = FALSE;
640 IWineD3DSwapChainImpl *targetSwapChain = NULL;
646 * for render->surface copy begin to begin of allocatedMemory
647 * unlock can be more easy
650 TRACE("locking a render target\n");
652 if (This->resource.allocatedMemory == NULL)
653 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
655 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
656 pLockedRect->pBits = This->resource.allocatedMemory;
659 vcheckGLcall("glFlush");
660 glGetIntegerv(GL_READ_BUFFER, &prev_read);
661 vcheckGLcall("glIntegerv");
662 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
663 vcheckGLcall("glIntegerv");
665 /* Here's what we have to do:
666 See if the swapchain has the same context as the renderTarget or the surface is the render target.
667 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
668 and use the front back buffer as required.
669 if not, we need to switch contexts and then switchback at the end.
671 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
672 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
674 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
675 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
676 if (swapchain && iface == swapchain->frontBuffer) {
677 TRACE("locking front\n");
678 glReadBuffer(GL_FRONT);
680 else if (iface == myDevice->renderTarget || backbuf) {
681 TRACE("locking back buffer\n");
682 glReadBuffer(GL_BACK);
683 } else if (iface == myDevice->depthStencilBuffer) {
684 FIXME("Stencil Buffer lock unsupported for now\n");
686 FIXME("(%p) Shouldn't have got here!\n", This);
687 glReadBuffer(GL_BACK);
689 } else if (swapchain != NULL) {
690 IWineD3DSwapChainImpl *implSwapChain;
691 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
692 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
693 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
695 glReadBuffer(GL_BACK);
696 } else if (iface == swapchain->frontBuffer) {
697 glReadBuffer(GL_FRONT);
698 } else if (iface == myDevice->depthStencilBuffer) {
699 FIXME("Stencil Buffer lock unsupported for now\n");
701 FIXME("Should have got here!\n");
702 glReadBuffer(GL_BACK);
705 /* We need to switch contexts to be able to read the buffer!!! */
706 FIXME("The buffer requested isn't in the current openGL context\n");
708 /* TODO: check the contexts, to see if were shared with the current context */
710 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
712 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
713 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
715 /** the depth stencil in openGL has a format of GL_FLOAT
716 * which should be good for WINED3DFMT_D16_LOCKABLE
718 * it is unclear what format the stencil buffer is in except.
719 * 'Each index is converted to fixed point...
720 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
721 * mappings in the table GL_PIXEL_MAP_S_TO_S.
722 * glReadPixels(This->lockedRect.left,
723 * This->lockedRect.bottom - j - 1,
724 * This->lockedRect.right - This->lockedRect.left,
726 * GL_DEPTH_COMPONENT,
728 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
729 *****************************************/
730 if (!notInContext) { /* Only read the buffer if it's in the current context */
731 switch(wined3d_settings.rendertargetlock_mode) {
735 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
740 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
741 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
746 static BOOL warned = FALSE;
748 ERR("Application tries to lock the render target, but render target locking is disabled\n");
755 TRACE("Resetting buffer\n");
757 glReadBuffer(prev_read);
758 vcheckGLcall("glReadBuffer");
762 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
765 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
768 glReadPixels(This->lockedRect.left,
769 This->lockedRect.bottom - j - 1,
770 This->lockedRect.right - This->lockedRect.left,
772 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
779 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
782 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
785 IWineD3DBaseTexture *pBaseTexture;
788 * as seen in msdn docs
790 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
792 /** Dirtify Container if needed */
793 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
794 TRACE("Making container dirty\n");
795 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
796 IWineD3DBaseTexture_Release(pBaseTexture);
798 TRACE("Surface is standalone, no need to dirty the container\n");
802 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
804 This->Flags |= SFLAG_LOCKED;
808 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
810 GLint prev_rasterpos[4];
812 BOOL storechanged = FALSE;
816 glDisable(GL_TEXTURE_2D);
817 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
818 glDisable(GL_TEXTURE_1D);
819 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
822 vcheckGLcall("glFlush");
823 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
824 vcheckGLcall("glIntegerv");
825 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
826 vcheckGLcall("glIntegerv");
827 glPixelZoom(1.0, -1.0);
828 vcheckGLcall("glPixelZoom");
830 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
831 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
832 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
834 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
835 vcheckGLcall("glRasterPos2f");
837 /* Some drivers(radeon dri, others?) don't like exceptions during
838 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
839 * after ReleaseDC. Reading it will cause an exception, which x11drv will
840 * catch to put the dib section in InSync mode, which leads to a crash
841 * and a blocked x server on my radeon card.
843 * The following lines read the dib section so it is put in inSync mode
844 * before glDrawPixels is called and the crash is prevented. There won't
845 * be any interfering gdi accesses, because UnlockRect is called from
846 * ReleaseDC, and the app won't use the dc any more afterwards.
848 if(This->Flags & SFLAG_DIBSECTION) {
850 read = This->resource.allocatedMemory[0];
853 switch (This->resource.format) {
854 /* No special care needed */
855 case WINED3DFMT_A4R4G4B4:
856 case WINED3DFMT_R5G6B5:
857 case WINED3DFMT_A1R5G5B5:
858 case WINED3DFMT_R8G8B8:
859 type = This->glDescription.glType;
860 fmt = This->glDescription.glFormat;
861 mem = This->resource.allocatedMemory;
864 case WINED3DFMT_X4R4G4B4:
867 unsigned short *data;
868 data = (unsigned short *)This->resource.allocatedMemory;
869 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
875 type = This->glDescription.glType;
876 fmt = This->glDescription.glFormat;
877 mem = This->resource.allocatedMemory;
881 case WINED3DFMT_X1R5G5B5:
884 unsigned short *data;
885 data = (unsigned short *)This->resource.allocatedMemory;
886 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
892 type = This->glDescription.glType;
893 fmt = This->glDescription.glFormat;
894 mem = This->resource.allocatedMemory;
898 case WINED3DFMT_X8R8G8B8:
900 /* make sure the X byte is set to alpha on, since it
901 could be any random value. This fixes the intro movie in Pirates! */
904 data = (unsigned int *)This->resource.allocatedMemory;
905 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
914 case WINED3DFMT_A8R8G8B8:
916 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
917 vcheckGLcall("glPixelStorei");
919 type = This->glDescription.glType;
920 fmt = This->glDescription.glFormat;
921 mem = This->resource.allocatedMemory;
925 case WINED3DFMT_A2R10G10B10:
927 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
928 vcheckGLcall("glPixelStorei");
930 type = This->glDescription.glType;
931 fmt = This->glDescription.glFormat;
932 mem = This->resource.allocatedMemory;
938 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
939 int height = This->glRect.bottom - This->glRect.top;
940 type = GL_UNSIGNED_BYTE;
943 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
945 ERR("Out of memory\n");
948 d3dfmt_convert_surface(This->resource.allocatedMemory,
957 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
960 type = This->glDescription.glType;
961 fmt = This->glDescription.glFormat;
962 mem = This->resource.allocatedMemory;
965 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
966 (This->lockedRect.bottom - This->lockedRect.top)-1,
969 checkGLcall("glDrawPixels");
970 glPixelZoom(1.0,1.0);
971 vcheckGLcall("glPixelZoom");
973 glRasterPos3iv(&prev_rasterpos[0]);
974 vcheckGLcall("glRasterPos3iv");
976 /* Reset to previous pack row length */
977 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
978 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
980 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
981 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
984 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
988 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
989 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
992 glTexCoord[0] = 0.0; /* left */
993 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
994 glTexCoord[2] = 0.0; /* top */
995 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
997 IWineD3DSurface_PreLoad(iface);
1001 /* Disable some fancy graphics effects */
1002 glDisable(GL_LIGHTING);
1003 checkGLcall("glDisable GL_LIGHTING");
1004 glDisable(GL_DEPTH_TEST);
1005 checkGLcall("glDisable GL_DEPTH_TEST");
1007 checkGLcall("glDisable GL_FOG");
1008 glDisable(GL_CULL_FACE);
1009 checkGLcall("glDisable GL_CULL_FACE");
1010 glDisable(GL_BLEND);
1011 checkGLcall("glDisable GL_BLEND");
1012 glDisable(GL_STENCIL_TEST);
1013 checkGLcall("glDisable GL_STENCIL_TEST");
1015 glEnable(GL_TEXTURE_2D);
1016 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1017 checkGLcall("glEnable glBindTexture");
1019 /* No filtering for blts */
1020 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1021 checkGLcall("glTexParameteri");
1022 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1023 checkGLcall("glTexParameteri");
1025 /* Start drawing a quad */
1028 glColor3d(1.0f, 1.0f, 1.0f);
1029 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1030 glVertex3f(0, 0, 0.0);
1032 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1033 glVertex3f(0, This->currentDesc.Height, 0.0);
1035 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1036 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1038 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1039 glVertex3f(This->currentDesc.Width, 0, 0.0);
1042 checkGLcall("glEnd");
1044 /* Unbind the texture */
1045 glBindTexture(GL_TEXTURE_2D, 0);
1046 checkGLcall("glEnable glBindTexture");
1051 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1052 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1053 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1054 const char *buffername = "";
1055 IWineD3DSwapChainImpl *swapchain = NULL;
1056 BOOL backbuf = FALSE;
1058 if (!(This->Flags & SFLAG_LOCKED)) {
1059 WARN("trying to Unlock an unlocked surf@%p\n", This);
1060 return WINED3DERR_INVALIDCALL;
1063 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1064 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1068 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1069 if(iface == swapchain->backBuffer[i]) {
1077 buffername = "backBuffer";
1078 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1079 buffername = "frontBuffer";
1080 } else if (iface == myDevice->depthStencilBuffer) {
1081 buffername = "depthStencilBuffer";
1082 } else if (iface == myDevice->renderTarget) {
1083 buffername = "renderTarget";
1087 if (swapchain != NULL) {
1088 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1091 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1093 if (!(This->Flags & SFLAG_DIRTY)) {
1094 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1098 if (0 == This->resource.usage) { /* classic surface */
1101 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1103 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1105 /****************************
1106 * TODO: Render targets are 'special' and
1107 * ?some? locking needs to be passed onto the context manager
1108 * so that it becomes possible to use auxiliary buffers, pbuffers
1109 * render-to-texture, shared, cached contexts etc...
1110 * ****************************/
1111 IWineD3DSwapChainImpl *implSwapChain;
1112 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1114 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1119 /* glDrawPixels transforms the raster position as though it was a vertex -
1120 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1121 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1122 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1124 if (iface == implSwapChain->frontBuffer) {
1125 glDrawBuffer(GL_FRONT);
1126 checkGLcall("glDrawBuffer GL_FRONT");
1127 } else if (backbuf || iface == myDevice->renderTarget) {
1128 glDrawBuffer(GL_BACK);
1129 checkGLcall("glDrawBuffer GL_BACK");
1132 /* Disable higher textures before calling glDrawPixels */
1133 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1134 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1135 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1136 checkGLcall("glActiveTextureARB");
1138 glDisable(GL_TEXTURE_2D);
1139 checkGLcall("glDisable GL_TEXTURE_2D");
1140 glDisable(GL_TEXTURE_1D);
1141 checkGLcall("glDisable GL_TEXTURE_1D");
1143 /* Activate texture 0, but don't disable it necessarilly */
1144 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1145 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1146 checkGLcall("glActiveTextureARB");
1149 /* And back buffers are not blended. Disable the depth test,
1150 that helps performance */
1151 glDisable(GL_BLEND);
1152 glDisable(GL_DEPTH_TEST);
1155 switch(wined3d_settings.rendertargetlock_mode) {
1159 flush_to_framebuffer_drawpixels(This);
1164 flush_to_framebuffer_texture(iface);
1169 static BOOL warned = FALSE;
1171 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1178 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1179 glDrawBuffer(GL_BACK);
1180 vcheckGLcall("glDrawBuffer");
1182 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1183 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1184 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1185 if (myDevice->stateBlock->renderState[D3DRS_FOGENABLE]) glEnable(GL_FOG);
1189 /** restore clean dirty state */
1190 IWineD3DSurface_CleanDirtyRect(iface);
1193 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1195 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1197 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1199 if (iface == myDevice->depthStencilBuffer) {
1200 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1202 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1206 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1210 This->Flags &= ~SFLAG_LOCKED;
1211 memset(&This->lockedRect, 0, sizeof(RECT));
1215 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1216 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1217 WINED3DLOCKED_RECT lock;
1224 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1226 TRACE("(%p)->(%p)\n",This,pHDC);
1228 if(This->Flags & SFLAG_USERPTR) {
1229 ERR("Not supported on surfaces with an application-provided surfaces\n");
1233 /* Give more detailed info for ddraw */
1234 if (This->Flags & SFLAG_DCINUSE)
1235 return DDERR_DCALREADYCREATED;
1237 /* Can't GetDC if the surface is locked */
1238 if (This->Flags & SFLAG_LOCKED)
1239 return WINED3DERR_INVALIDCALL;
1241 memset(&lock, 0, sizeof(lock)); /* To be sure */
1243 /* Create a DIB section if there isn't a hdc yet */
1246 SYSTEM_INFO sysInfo;
1248 if(This->Flags & SFLAG_ACTIVELOCK) {
1249 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1252 switch (This->bytesPerPixel) {
1255 /* Allocate extra space to store the RGB bit masks. */
1256 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1260 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1264 /* Allocate extra space for a palette. */
1265 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1266 sizeof(BITMAPINFOHEADER)
1268 * (1 << (This->bytesPerPixel * 8)));
1273 return E_OUTOFMEMORY;
1275 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1276 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1277 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1278 * add an extra line to the dib section
1280 GetSystemInfo(&sysInfo);
1281 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1283 TRACE("Adding an extra line to the dib section\n");
1286 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1287 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1288 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1289 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1290 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1291 /* Use the full pow2 image size(assigned below) because LockRect
1292 * will need it for a full glGetTexImage call
1295 b_info->bmiHeader.biWidth = This->pow2Width;
1296 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1297 b_info->bmiHeader.biSizeImage = This->resource.size;
1299 b_info->bmiHeader.biPlanes = 1;
1300 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1302 b_info->bmiHeader.biXPelsPerMeter = 0;
1303 b_info->bmiHeader.biYPelsPerMeter = 0;
1304 b_info->bmiHeader.biClrUsed = 0;
1305 b_info->bmiHeader.biClrImportant = 0;
1307 /* Get the bit masks */
1308 masks = (DWORD *) &(b_info->bmiColors);
1309 switch (This->resource.format) {
1310 case WINED3DFMT_R8G8B8:
1311 usage = DIB_RGB_COLORS;
1312 b_info->bmiHeader.biCompression = BI_RGB;
1315 case WINED3DFMT_X1R5G5B5:
1316 case WINED3DFMT_A1R5G5B5:
1317 case WINED3DFMT_A4R4G4B4:
1318 case WINED3DFMT_X4R4G4B4:
1319 case WINED3DFMT_R3G3B2:
1320 case WINED3DFMT_A8R3G3B2:
1321 case WINED3DFMT_A2B10G10R10:
1322 case WINED3DFMT_A8B8G8R8:
1323 case WINED3DFMT_X8B8G8R8:
1324 case WINED3DFMT_A2R10G10B10:
1325 case WINED3DFMT_R5G6B5:
1326 case WINED3DFMT_A16B16G16R16:
1328 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1329 masks[0] = formatEntry->redMask;
1330 masks[1] = formatEntry->greenMask;
1331 masks[2] = formatEntry->blueMask;
1335 /* Don't know palette */
1336 b_info->bmiHeader.biCompression = BI_RGB;
1341 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1343 HeapFree(GetProcessHeap(), 0, b_info);
1344 return HRESULT_FROM_WIN32(GetLastError());
1347 TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1348 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1351 if (!This->dib.DIBsection) {
1352 ERR("CreateDIBSection failed!\n");
1353 HeapFree(GetProcessHeap(), 0, b_info);
1354 return HRESULT_FROM_WIN32(GetLastError());
1357 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1359 /* copy the existing surface to the dib section */
1360 if(This->resource.allocatedMemory) {
1361 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1362 /* We won't need that any more */
1363 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1365 /* This is to make LockRect read the gl Texture although memory is allocated */
1366 This->Flags |= SFLAG_GLDIRTY;
1369 HeapFree(GetProcessHeap(), 0, b_info);
1371 /* Use the dib section from now on */
1372 This->resource.allocatedMemory = This->dib.bitmap_data;
1374 /* Now allocate a HDC */
1375 This->hDC = CreateCompatibleDC(0);
1376 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1377 TRACE("using wined3d palette %p\n", This->palette);
1378 SelectPalette(This->hDC,
1379 This->palette ? This->palette->hpal : 0,
1382 This->Flags |= SFLAG_DIBSECTION;
1385 /* Lock the surface */
1386 hr = IWineD3DSurface_LockRect(iface,
1391 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1392 /* keep the dib section */
1396 if(This->resource.format == WINED3DFMT_P8 ||
1397 This->resource.format == WINED3DFMT_A8P8) {
1400 PALETTEENTRY ent[256];
1402 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1403 for (n=0; n<256; n++) {
1404 col[n].rgbRed = ent[n].peRed;
1405 col[n].rgbGreen = ent[n].peGreen;
1406 col[n].rgbBlue = ent[n].peBlue;
1407 col[n].rgbReserved = 0;
1410 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1412 for (n=0; n<256; n++) {
1413 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1414 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1415 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1416 col[n].rgbReserved = 0;
1420 SetDIBColorTable(This->hDC, 0, 256, col);
1424 TRACE("returning %p\n",*pHDC);
1425 This->Flags |= SFLAG_DCINUSE;
1430 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1431 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1433 TRACE("(%p)->(%p)\n",This,hDC);
1435 if (!(This->Flags & SFLAG_DCINUSE))
1436 return D3DERR_INVALIDCALL;
1438 /* we locked first, so unlock now */
1439 IWineD3DSurface_UnlockRect(iface);
1441 This->Flags &= ~SFLAG_DCINUSE;
1446 /* ******************************************************
1447 IWineD3DSurface Internal (No mapping to directx api) parts follow
1448 ****************************************************** */
1450 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) {
1451 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1452 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1454 /* Default values: From the surface */
1455 *format = formatEntry->glFormat;
1456 *internal = formatEntry->glInternal;
1457 *type = formatEntry->glType;
1458 *convert = NO_CONVERSION;
1459 *target_bpp = This->bytesPerPixel;
1461 /* Ok, now look if we have to do any conversion */
1462 switch(This->resource.format) {
1467 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1468 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1470 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1472 *internal = GL_RGBA;
1473 *type = GL_UNSIGNED_BYTE;
1475 if(colorkey_active) {
1476 *convert = CONVERT_PALETTED_CK;
1478 *convert = CONVERT_PALETTED;
1484 case WINED3DFMT_R3G3B2:
1485 /* **********************
1486 GL_UNSIGNED_BYTE_3_3_2
1487 ********************** */
1488 if (colorkey_active) {
1489 /* This texture format will never be used.. So do not care about color keying
1490 up until the point in time it will be needed :-) */
1491 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1495 case WINED3DFMT_R5G6B5:
1496 if (colorkey_active) {
1497 *convert = CONVERT_CK_565;
1499 *internal = GL_RGBA;
1500 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1504 case WINED3DFMT_R8G8B8:
1505 if (colorkey_active) {
1506 *convert = CONVERT_CK_RGB24;
1508 *internal = GL_RGBA;
1509 *type = GL_UNSIGNED_INT_8_8_8_8;
1514 case WINED3DFMT_X8R8G8B8:
1515 if (colorkey_active) {
1516 *convert = CONVERT_RGB32_888;
1518 *internal = GL_RGBA;
1519 *type = GL_UNSIGNED_INT_8_8_8_8;
1523 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1524 case WINED3DFMT_A4R4G4B4:
1525 if (colorkey_active)
1527 *convert = CONVERT_CK_4444_ARGB;
1529 *internal = GL_RGBA;
1530 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1534 case WINED3DFMT_A1R5G5B5:
1535 if (colorkey_active)
1537 *convert = CONVERT_CK_1555;
1540 case WINED3DFMT_A8R8G8B8:
1541 if (colorkey_active)
1543 *convert = CONVERT_CK_8888_ARGB;
1545 *internal = GL_RGBA;
1546 *type = GL_UNSIGNED_INT_8_8_8_8;
1557 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1558 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1563 memcpy(dst, src, len * surf->bytesPerPixel);
1566 case CONVERT_PALETTED:
1567 case CONVERT_PALETTED_CK:
1569 IWineD3DPaletteImpl* pal = surf->palette;
1575 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1579 /* Still no palette? Use the device's palette */
1580 /* Get the surface's palette */
1581 for (i = 0; i < 256; i++) {
1582 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1584 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1585 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1586 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1587 if ((convert == CONVERT_PALETTED_CK) &&
1588 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1589 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1590 /* We should maybe here put a more 'neutral' color than the standard bright purple
1591 one often used by application to prevent the nice purple borders when bi-linear
1599 TRACE("Using surface palette %p\n", pal);
1600 /* Get the surface's palette */
1601 for (i = 0; i < 256; i++) {
1602 table[i][0] = pal->palents[i].peRed;
1603 table[i][1] = pal->palents[i].peGreen;
1604 table[i][2] = pal->palents[i].peBlue;
1605 if ((convert == CONVERT_PALETTED_CK) &&
1606 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1607 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1608 /* We should maybe here put a more 'neutral' color than the standard bright purple
1609 one often used by application to prevent the nice purple borders when bi-linear
1618 for (x = 0; x < len; x++) {
1619 BYTE color = *src++;
1620 *dst++ = table[color][0];
1621 *dst++ = table[color][1];
1622 *dst++ = table[color][2];
1623 *dst++ = table[color][3];
1628 case CONVERT_CK_565:
1630 /* Converting the 565 format in 5551 packed to emulate color-keying.
1632 Note : in all these conversion, it would be best to average the averaging
1633 pixels to get the color of the pixel that will be color-keyed to
1634 prevent 'color bleeding'. This will be done later on if ever it is
1637 Note2: when using color-keying + alpha, are the alpha bits part of the
1638 color-space or not ?
1641 WORD *Source = (WORD *) src;
1642 WORD *Dest = (WORD *) dst;
1644 TRACE("Color keyed 565\n");
1646 for (x = 0; x < len; x++ ) {
1647 WORD color = *Source++;
1648 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1649 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1650 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1658 case CONVERT_CK_1555:
1661 WORD *Source = (WORD *) src;
1662 WORD *Dest = (WORD *) dst;
1664 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1665 WORD color = *Source++;
1666 *Dest = (color & 0x7FFF);
1667 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1668 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1669 *Dest |= (color & 0x8000);
1675 case CONVERT_CK_4444_ARGB:
1677 /* Move the four Alpha bits... */
1679 WORD *Source = (WORD *) src;
1680 WORD *Dest = (WORD *) dst;
1682 for (x = 0; x < len; x++) {
1683 WORD color = *Source++;
1684 *dst = (color & 0x0FFF) << 4;
1685 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1686 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1687 *Dest |= (color & 0xF000) >> 12;
1693 ERR("Unsupported conversation type %d\n", convert);
1699 /* This function is used in case of 8bit paletted textures to upload the palette.
1700 For now it only supports GL_EXT_paletted_texture extension but support for other
1701 extensions like ARB_fragment_program and ATI_fragment_shaders will be added aswell.
1703 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1704 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1705 IWineD3DPaletteImpl* pal = This->palette;
1710 /* Still no palette? Use the device's palette */
1711 /* Get the surface's palette */
1712 for (i = 0; i < 256; i++) {
1713 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1715 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1716 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1717 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1718 if ((convert == CONVERT_PALETTED_CK) &&
1719 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1720 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1721 /* We should maybe here put a more 'neutral' color than the standard bright purple
1722 one often used by application to prevent the nice purple borders when bi-linear
1730 TRACE("Using surface palette %p\n", pal);
1731 /* Get the surface's palette */
1732 for (i = 0; i < 256; i++) {
1733 table[i][0] = pal->palents[i].peRed;
1734 table[i][1] = pal->palents[i].peGreen;
1735 table[i][2] = pal->palents[i].peBlue;
1736 if ((convert == CONVERT_PALETTED_CK) &&
1737 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1738 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1739 /* We should maybe here put a more 'neutral' color than the standard bright purple
1740 one often used by application to prevent the nice purple borders when bi-linear
1748 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1751 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1752 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1754 if (This->Flags & SFLAG_INTEXTURE) {
1755 TRACE("Surface already in texture\n");
1758 if (This->Flags & SFLAG_DIRTY) {
1759 TRACE("Reloading because surface is dirty\n");
1760 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1761 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1762 /* Reload: vice versa OR */
1763 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1764 /* Also reload: Color key is active AND the color key has changed */
1765 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1766 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1767 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1768 TRACE("Reloading because of color keying\n");
1770 TRACE("surface isn't dirty\n");
1774 This->Flags &= ~SFLAG_DIRTY;
1776 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1777 * These resources are not bound by device size or format restrictions. Because of this,
1778 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1779 * However, these resources can always be created, locked, and copied.
1781 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1783 FIXME("(%p) Operation not supported for scratch textures\n",This);
1784 return WINED3DERR_INVALIDCALL;
1787 if (This->Flags & SFLAG_INPBUFFER) {
1790 if (This->glDescription.level != 0)
1791 FIXME("Surface in texture is only supported for level 0\n");
1792 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1793 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1794 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1795 This->resource.format == WINED3DFMT_DXT5)
1796 FIXME("Format %d not supported\n", This->resource.format);
1799 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1800 vcheckGLcall("glGetIntegerv");
1801 glReadBuffer(GL_BACK);
1802 vcheckGLcall("glReadBuffer");
1804 glCopyTexImage2D(This->glDescription.target,
1805 This->glDescription.level,
1806 This->glDescription.glFormatInternal,
1809 This->currentDesc.Width,
1810 This->currentDesc.Height,
1813 checkGLcall("glCopyTexImage2D");
1814 glReadBuffer(prevRead);
1815 vcheckGLcall("glReadBuffer");
1816 TRACE("Updating target %d\n", This->glDescription.target);
1817 This->Flags |= SFLAG_INTEXTURE;
1823 /* TODO: Compressed non-power 2 support */
1825 if (This->resource.format == WINED3DFMT_DXT1 ||
1826 This->resource.format == WINED3DFMT_DXT2 ||
1827 This->resource.format == WINED3DFMT_DXT3 ||
1828 This->resource.format == WINED3DFMT_DXT4 ||
1829 This->resource.format == WINED3DFMT_DXT5) {
1830 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1831 FIXME("Using DXT1/3/5 without advertized support\n");
1832 } else if (This->resource.allocatedMemory) {
1833 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1834 This->glDescription.target,
1835 This->glDescription.level,
1836 This->glDescription.glFormatInternal,
1837 This->currentDesc.Width,
1838 This->currentDesc.Height,
1840 This->resource.size,
1841 This->resource.allocatedMemory);
1845 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1846 This->glDescription.level,
1847 This->glDescription.glFormatInternal,
1848 This->currentDesc.Width,
1849 This->currentDesc.Height,
1851 This->resource.size,
1852 This->resource.allocatedMemory);
1853 checkGLcall("glCommpressedTexImage2D");
1857 if(!(This->Flags & SFLAG_DONOTFREE)){
1858 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1859 This->resource.allocatedMemory = NULL;
1863 GLenum format, internal, type;
1864 CONVERT_TYPES convert;
1869 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1870 This->Flags |= SFLAG_GLCKEY;
1871 This->glCKey = This->SrcBltCKey;
1873 else This->Flags &= ~SFLAG_GLCKEY;
1874 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1876 /* The pitch is in 'length' not in bytes */
1877 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1878 pitch = This->currentDesc.Width;
1880 pitch = This->pow2Width;
1882 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1883 int height = This->glRect.bottom - This->glRect.top;
1885 mem = HeapAlloc(GetProcessHeap(), 0, pitch * height * bpp);
1887 ERR("Out of memory %d, %d!\n", pitch, height);
1888 return WINED3DERR_OUTOFVIDEOMEMORY;
1890 d3dfmt_convert_surface(This->resource.allocatedMemory,
1896 This->Flags |= SFLAG_CONVERTED;
1897 } else if(This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1898 d3dfmt_p8_upload_palette(iface, convert);
1899 This->Flags &= ~SFLAG_CONVERTED;
1900 mem = This->resource.allocatedMemory;
1902 This->Flags &= ~SFLAG_CONVERTED;
1903 mem = This->resource.allocatedMemory;
1906 /* Make sure the correct pitch is used */
1907 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
1909 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1910 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1913 TRACE("non power of two support\n");
1915 TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1916 This->glDescription.target,
1917 This->glDescription.level,
1918 debug_d3dformat(This->resource.format),
1919 This->glDescription.glFormatInternal,
1923 This->glDescription.glFormat,
1924 This->glDescription.glType,
1927 glTexImage2D(This->glDescription.target,
1928 This->glDescription.level,
1929 This->glDescription.glFormatInternal,
1933 This->glDescription.glFormat,
1934 This->glDescription.glType,
1937 checkGLcall("glTexImage2D");
1938 if (This->resource.allocatedMemory != NULL) {
1939 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1940 /* And map the non-power two data into the top left corner */
1942 This->glDescription.target,
1943 This->glDescription.level,
1946 This->currentDesc.Width,
1947 This->currentDesc.Height,
1948 This->glDescription.glFormat,
1949 This->glDescription.glType,
1950 This->resource.allocatedMemory
1952 checkGLcall("glTexSubImage2D");
1958 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1959 This->glDescription.target,
1960 This->glDescription.level,
1961 debug_d3dformat(This->resource.format),
1962 This->glDescription.glFormatInternal,
1963 This->glRect.right - This->glRect.left,
1964 This->glRect.bottom - This->glRect.top,
1966 This->glDescription.glFormat,
1967 This->glDescription.glType,
1972 /* OK, create the texture */
1973 glTexImage2D(This->glDescription.target,
1974 This->glDescription.level,
1976 This->glRect.right - This->glRect.left,
1977 This->glRect.bottom - This->glRect.top,
1983 checkGLcall("glTexImage2D");
1987 if(mem != This->resource.allocatedMemory)
1988 HeapFree(GetProcessHeap(), 0, mem);
1992 static unsigned int gen = 0;
1995 if ((gen % 10) == 0) {
1996 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1997 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2000 * debugging crash code
2008 if(!(This->Flags & SFLAG_DONOTFREE)){
2009 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
2010 This->resource.allocatedMemory = NULL;
2013 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2021 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
2024 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2025 char *allocatedMemory;
2027 IWineD3DSwapChain *swapChain = NULL;
2032 Textures my not be stored in ->allocatedgMemory and a GlTexture
2033 so we should lock the surface before saving a snapshot, or at least check that
2035 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2036 by calling GetTexImage and in compressed form by calling
2037 GetCompressedTexImageARB. Queried compressed images can be saved and
2038 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2039 texture images do not need to be processed by the GL and should
2040 significantly improve texture loading performance relative to uncompressed
2043 /* Setup the width and height to be the internal texture width and height. */
2044 width = This->pow2Width;
2045 height = This->pow2Height;
2046 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
2047 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2049 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
2050 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
2053 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
2054 glEnable(GL_TEXTURE_2D);
2056 glGenTextures(1, &tmpTexture);
2057 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2059 glTexImage2D(GL_TEXTURE_2D,
2066 GL_UNSIGNED_INT_8_8_8_8_REV,
2069 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2070 vcheckGLcall("glGetIntegerv");
2071 glReadBuffer(GL_BACK);
2072 vcheckGLcall("glReadBuffer");
2073 glCopyTexImage2D(GL_TEXTURE_2D,
2082 checkGLcall("glCopyTexImage2D");
2083 glReadBuffer(prevRead);
2086 } else { /* bind the real texture */
2087 IWineD3DSurface_PreLoad(iface);
2089 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2091 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2092 glGetTexImage(GL_TEXTURE_2D,
2093 This->glDescription.level,
2095 GL_UNSIGNED_INT_8_8_8_8_REV,
2097 checkGLcall("glTexImage2D");
2099 glBindTexture(GL_TEXTURE_2D, 0);
2100 glDeleteTextures(1, &tmpTexture);
2104 f = fopen(filename, "w+");
2106 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2107 return WINED3DERR_INVALIDCALL;
2109 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2110 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2125 fwrite(&width,2,1,f);
2127 fwrite(&height,2,1,f);
2132 /* 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*/
2134 textureRow = allocatedMemory + (width * (height - 1) *4);
2136 textureRow = allocatedMemory;
2137 for (y = 0 ; y < height; y++) {
2138 for (i = 0; i < width; i++) {
2139 color = *((DWORD*)textureRow);
2140 fputc((color >> 16) & 0xFF, f); /* B */
2141 fputc((color >> 8) & 0xFF, f); /* G */
2142 fputc((color >> 0) & 0xFF, f); /* R */
2143 fputc((color >> 24) & 0xFF, f); /* A */
2146 /* take two rows of the pointer to the texture memory */
2148 (textureRow-= width << 3);
2151 TRACE("Closing file\n");
2155 IWineD3DSwapChain_Release(swapChain);
2157 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2161 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2162 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2163 This->Flags &= ~SFLAG_DIRTY;
2164 This->dirtyRect.left = This->currentDesc.Width;
2165 This->dirtyRect.top = This->currentDesc.Height;
2166 This->dirtyRect.right = 0;
2167 This->dirtyRect.bottom = 0;
2168 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2169 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2174 * Slightly inefficient way to handle multiple dirty rects but it works :)
2176 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2177 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2178 IWineD3DBaseTexture *baseTexture = NULL;
2179 This->Flags |= SFLAG_DIRTY;
2180 if (NULL != pDirtyRect) {
2181 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2182 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2183 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2184 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2186 This->dirtyRect.left = 0;
2187 This->dirtyRect.top = 0;
2188 This->dirtyRect.right = This->currentDesc.Width;
2189 This->dirtyRect.bottom = This->currentDesc.Height;
2191 TRACE("(%p) : Dirty?%ld, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2192 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2193 /* if the container is a basetexture then mark it dirty. */
2194 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2195 TRACE("Passing to conatiner\n");
2196 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2197 IWineD3DBaseTexture_Release(baseTexture);
2202 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2203 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2205 TRACE("This %p, container %p\n", This, container);
2207 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2209 TRACE("Setting container to %p from %p\n", container, This->container);
2210 This->container = container;
2215 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2216 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2217 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2219 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2220 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2221 return WINED3DERR_INVALIDCALL;
2224 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2225 if (format == WINED3DFMT_UNKNOWN) {
2226 This->resource.size = 0;
2227 } else if (format == WINED3DFMT_DXT1) {
2228 /* DXT1 is half byte per pixel */
2229 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2231 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2232 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2233 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2235 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2239 /* Setup some glformat defaults */
2240 This->glDescription.glFormat = formatEntry->glFormat;
2241 This->glDescription.glFormatInternal = formatEntry->glInternal;
2242 This->glDescription.glType = formatEntry->glType;
2244 if (format != WINED3DFMT_UNKNOWN) {
2245 This->bytesPerPixel = formatEntry->bpp;
2246 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2248 This->bytesPerPixel = 0;
2252 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2254 This->resource.format = format;
2256 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2261 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2262 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2264 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2265 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2266 ERR("Not supported on render targets\n");
2267 return WINED3DERR_INVALIDCALL;
2270 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2271 WARN("Surface is locked or the HDC is in use\n");
2272 return WINED3DERR_INVALIDCALL;
2275 if(Mem && Mem != This->resource.allocatedMemory) {
2277 /* Do I have to copy the old surface content? */
2278 if(This->Flags & SFLAG_DIBSECTION) {
2279 /* Release the DC. No need to hold the critical section for the update
2280 * Thread because this thread runs only on front buffers, but this method
2281 * fails for render targets in the check above.
2283 SelectObject(This->hDC, This->dib.holdbitmap);
2284 DeleteDC(This->hDC);
2285 /* Release the DIB section */
2286 DeleteObject(This->dib.DIBsection);
2287 This->dib.bitmap_data = NULL;
2288 This->resource.allocatedMemory = NULL;
2290 This->Flags &= ~SFLAG_DIBSECTION;
2291 } else if(!(This->Flags & SFLAG_USERPTR)) {
2292 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2294 This->resource.allocatedMemory = Mem;
2295 This->Flags |= SFLAG_USERPTR;
2296 } else if(This->Flags & SFLAG_USERPTR) {
2297 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2298 This->resource.allocatedMemory = NULL;
2299 This->Flags &= ~SFLAG_USERPTR;
2304 /* TODO: replace this function with context management routines */
2305 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2306 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2309 This->Flags |= SFLAG_INPBUFFER;
2311 This->Flags &= ~SFLAG_INPBUFFER;
2315 This->Flags |= SFLAG_INTEXTURE;
2317 This->Flags &= ~SFLAG_INTEXTURE;
2323 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2324 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2325 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2326 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2328 /* Flipping is only supported on RenderTargets */
2329 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2332 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2333 * FIXME("(%p) Target override is not supported by now\n", This);
2334 * Additionally, it isn't really possible to support triple-buffering
2335 * properly on opengl at all
2339 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2340 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2343 /* Not called from the VTable */
2344 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2346 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2347 IWineD3DSwapChainImpl *swapchain = NULL;
2348 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2351 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2353 /* Get the swapchain. One of the surfaces has to be a primary surface */
2354 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2355 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2357 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2358 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2359 else return WINED3DERR_INVALIDCALL;
2365 rect.x1 = DestRect->left;
2366 rect.y1 = DestRect->top;
2367 rect.x2 = DestRect->right;
2368 rect.y2 = DestRect->bottom;
2372 rect.x2 = This->currentDesc.Width;
2373 rect.y2 = This->currentDesc.Height;
2376 /* Half-life does a Blt from the back buffer to the front buffer,
2377 * Full surface size, no flags... Use present instead
2381 /* First, check if we can do a Flip */
2383 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2385 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2386 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2393 /* Check the Destination rect and the surface sizes */
2395 (rect.x1 == 0) && (rect.y1 == 0) &&
2396 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2397 (This->currentDesc.Width == Src->currentDesc.Width) &&
2398 (This->currentDesc.Height == Src->currentDesc.Height)) {
2399 /* These flags are unimportant for the flag check, remove them */
2401 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2402 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2404 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2406 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2407 * take very long, while a flip is fast.
2408 * This applies to Half-Life, which does such Blts every time it finished
2409 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2410 * menu. This is also used by all apps when they do windowed rendering
2412 * The problem is that flipping is not really the same as copying. After a
2413 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2414 * untouched. Therefore it's necessary to override the swap effect
2415 * and to set it back after the flip.
2418 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2420 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2421 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2422 NULL, NULL, 0, NULL);
2424 swapchain->presentParms.SwapEffect = orig_swap;
2431 /* Blt from texture to rendertarget? */
2432 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2433 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2435 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2436 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2437 float glTexCoord[4];
2439 DDCOLORKEY oldBltCKey = {0,0};
2440 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2444 RECT SourceRectangle;
2447 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2450 SourceRectangle.left = SrcRect->left;
2451 SourceRectangle.right = SrcRect->right;
2452 SourceRectangle.top = SrcRect->top;
2453 SourceRectangle.bottom = SrcRect->bottom;
2455 SourceRectangle.left = 0;
2456 SourceRectangle.right = Src->currentDesc.Width;
2457 SourceRectangle.top = 0;
2458 SourceRectangle.bottom = Src->currentDesc.Height;
2461 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2462 /* Fall back to software */
2463 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2464 SourceRectangle.left, SourceRectangle.top,
2465 SourceRectangle.right, SourceRectangle.bottom);
2466 return WINED3DERR_INVALIDCALL;
2469 /* Color keying: Check if we have to do a color keyed blt,
2470 * and if not check if a color key is activated.
2472 oldCKey = Src->CKeyFlags;
2473 if(!(Flags & DDBLT_KEYSRC) &&
2474 Src->CKeyFlags & DDSD_CKSRCBLT) {
2475 /* Ok, the surface has a color key, but we shall not use it -
2476 * Deactivate it for now, LoadTexture will catch this
2478 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2482 if(Flags & DDBLT_KEYDEST) {
2483 oldBltCKey = This->SrcBltCKey;
2484 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2485 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2487 This->SrcBltCKey = This->DestBltCKey;
2488 } else if (Flags & DDBLT_KEYSRC)
2489 oldBltCKey = This->SrcBltCKey;
2491 /* Now load the surface */
2492 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2496 /* Save all the old stuff until we have a proper opengl state manager */
2497 oldLight = glIsEnabled(GL_LIGHTING);
2498 oldFog = glIsEnabled(GL_FOG);
2499 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2500 oldBlend = glIsEnabled(GL_BLEND);
2501 oldCull = glIsEnabled(GL_CULL_FACE);
2502 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2503 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2505 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2506 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2507 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2508 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2510 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2511 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2512 TRACE("Drawing to front buffer\n");
2513 glDrawBuffer(GL_FRONT);
2514 checkGLcall("glDrawBuffer GL_FRONT");
2517 /* Unbind the old texture */
2518 glBindTexture(GL_TEXTURE_2D, 0);
2520 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2521 /* We use texture unit 0 for blts */
2522 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2523 checkGLcall("glActiveTextureARB");
2525 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2528 /* Disable some fancy graphics effects */
2529 glDisable(GL_LIGHTING);
2530 checkGLcall("glDisable GL_LIGHTING");
2531 glDisable(GL_DEPTH_TEST);
2532 checkGLcall("glDisable GL_DEPTH_TEST");
2534 checkGLcall("glDisable GL_FOG");
2535 glDisable(GL_BLEND);
2536 checkGLcall("glDisable GL_BLEND");
2537 glDisable(GL_CULL_FACE);
2538 checkGLcall("glDisable GL_CULL_FACE");
2539 glDisable(GL_STENCIL_TEST);
2540 checkGLcall("glDisable GL_STENCIL_TEST");
2542 /* Ok, we need 2d textures, but not 1D or 3D */
2543 glDisable(GL_TEXTURE_1D);
2544 checkGLcall("glDisable GL_TEXTURE_1D");
2545 glEnable(GL_TEXTURE_2D);
2546 checkGLcall("glEnable GL_TEXTURE_2D");
2547 glDisable(GL_TEXTURE_3D);
2548 checkGLcall("glDisable GL_TEXTURE_3D");
2550 /* Bind the texture */
2551 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2552 checkGLcall("glBindTexture");
2554 glEnable(GL_SCISSOR_TEST);
2556 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2558 /* No filtering for blts */
2559 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2561 checkGLcall("glTexParameteri");
2562 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2564 checkGLcall("glTexParameteri");
2565 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2566 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2567 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2568 checkGLcall("glTexEnvi");
2570 /* This is for color keying */
2571 if(Flags & DDBLT_KEYSRC) {
2572 glEnable(GL_ALPHA_TEST);
2573 checkGLcall("glEnable GL_ALPHA_TEST");
2574 glAlphaFunc(GL_NOTEQUAL, 0.0);
2575 checkGLcall("glAlphaFunc\n");
2577 glDisable(GL_ALPHA_TEST);
2578 checkGLcall("glDisable GL_ALPHA_TEST");
2581 /* Draw a textured quad
2583 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2587 glColor3d(1.0f, 1.0f, 1.0f);
2588 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2593 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2594 glVertex3f(rect.x1, rect.y2, 0.0);
2596 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2601 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2606 checkGLcall("glEnd");
2608 /* Unbind the texture */
2609 glBindTexture(GL_TEXTURE_2D, 0);
2610 checkGLcall("glEnable glBindTexture");
2612 /* Restore the old settings */
2614 glEnable(GL_LIGHTING);
2615 checkGLcall("glEnable GL_LIGHTING");
2619 checkGLcall("glEnable GL_FOG");
2622 glEnable(GL_DEPTH_TEST);
2623 checkGLcall("glEnable GL_DEPTH_TEST");
2627 checkGLcall("glEnable GL_BLEND");
2630 glEnable(GL_CULL_FACE);
2631 checkGLcall("glEnable GL_CULL_FACE");
2634 glEnable(GL_STENCIL_TEST);
2635 checkGLcall("glEnable GL_STENCIL_TEST");
2638 glDisable(GL_ALPHA_TEST);
2639 checkGLcall("glDisable GL_ALPHA_TEST");
2641 glEnable(GL_ALPHA_TEST);
2642 checkGLcall("glEnable GL_ALPHA_TEST");
2645 glAlphaFunc(alphafunc, alpharef);
2646 checkGLcall("glAlphaFunc\n");
2648 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2649 glDrawBuffer(oldDraw);
2652 /* Restore the color key flags */
2653 if(oldCKey != Src->CKeyFlags) {
2654 Src->CKeyFlags = oldCKey;
2657 /* Restore the old color key */
2658 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2659 This->SrcBltCKey = oldBltCKey;
2663 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2664 This->Flags |= SFLAG_GLDIRTY;
2670 /* Blt from rendertarget to texture? */
2671 if( (SrcSurface == swapchain->frontBuffer) ||
2672 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2673 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2674 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2679 TRACE("Blt from rendertarget to texture\n");
2681 /* Call preload for the surface to make sure it isn't dirty */
2682 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2685 srect.x1 = SrcRect->left;
2686 srect.y1 = SrcRect->top;
2687 srect.x2 = SrcRect->right;
2688 srect.y2 = SrcRect->bottom;
2692 srect.x2 = Src->currentDesc.Width;
2693 srect.y2 = Src->currentDesc.Height;
2698 /* Bind the target texture */
2699 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2700 checkGLcall("glBindTexture");
2701 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2702 glReadBuffer(GL_BACK);
2704 glReadBuffer(GL_FRONT);
2706 checkGLcall("glReadBuffer");
2708 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2709 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2711 /* I have to process this row by row to swap the image,
2712 * otherwise it would be upside down, so streching in y direction
2713 * doesn't cost extra time
2715 * However, streching in x direction can be avoided if not necessary
2717 for(row = rect.y1; row < rect.y2; row++) {
2718 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2719 /* Well, that stuff works, but it's very slow.
2720 * find a better way instead
2723 for(col = rect.x1; col < rect.x2; col++) {
2724 glCopyTexSubImage2D(GL_TEXTURE_2D,
2726 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2727 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2731 glCopyTexSubImage2D(GL_TEXTURE_2D,
2733 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2734 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2739 vcheckGLcall("glCopyTexSubImage2D");
2742 if(!(This->Flags & SFLAG_DONOTFREE)) {
2743 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2744 This->resource.allocatedMemory = NULL;
2746 This->Flags |= SFLAG_GLDIRTY;
2754 if (Flags & DDBLT_COLORFILL) {
2755 /* This is easy to handle for the D3D Device... */
2757 IWineD3DSwapChainImpl *implSwapChain;
2759 TRACE("Colorfill\n");
2761 /* The color as given in the Blt function is in the format of the frame-buffer...
2762 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2764 if (This->resource.format == WINED3DFMT_P8) {
2765 if (This->palette) {
2766 color = ((0xFF000000) |
2767 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2768 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2769 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2774 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2775 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2778 color = ((0xFF000000) |
2779 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2780 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2781 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2784 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2785 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2786 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2788 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2789 color = DDBltFx->u5.dwFillColor;
2792 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2793 return WINED3DERR_INVALIDCALL;
2796 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2797 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2798 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2799 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2800 glDrawBuffer(GL_BACK);
2801 checkGLcall("glDrawBuffer(GL_BACK)");
2803 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2804 glDrawBuffer(GL_FRONT);
2805 checkGLcall("glDrawBuffer(GL_FRONT)");
2808 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2809 return WINED3DERR_INVALIDCALL;
2812 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2814 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2815 1 /* Number of rectangles */,
2822 /* Restore the original draw buffer */
2823 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2824 glDrawBuffer(GL_BACK);
2825 vcheckGLcall("glDrawBuffer");
2831 /* Default: Fall back to the generic blt */
2832 return WINED3DERR_INVALIDCALL;
2835 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2836 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2837 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2838 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2839 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2841 /* Special cases for RenderTargets */
2842 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2843 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2844 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2847 /* For the rest call the X11 surface implementation.
2848 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2849 * other Blts are rather rare
2851 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2854 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2855 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2856 TRACE("(%p)->(%lx)\n", This, Flags);
2861 case DDGBS_ISBLTDONE:
2865 return DDERR_INVALIDPARAMS;
2869 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2870 /* XXX: DDERR_INVALIDSURFACETYPE */
2872 TRACE("(%p)->(%08lx)\n",iface,Flags);
2875 case DDGFS_ISFLIPDONE:
2879 return DDERR_INVALIDPARAMS;
2883 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2885 TRACE("(%p)\n", This);
2887 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2890 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2891 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2892 TRACE("(%p)\n", This);
2894 /* So far we don't lose anything :) */
2895 This->Flags &= ~SFLAG_LOST;
2899 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2900 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2901 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2902 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2904 /* Special cases for RenderTargets */
2905 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2906 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2908 RECT SrcRect, DstRect;
2912 SrcRect.left = rsrc->left;
2913 SrcRect.top= rsrc->top;
2914 SrcRect.bottom = rsrc->bottom;
2915 SrcRect.right = rsrc->right;
2919 SrcRect.right = srcImpl->currentDesc.Width;
2920 SrcRect.bottom = srcImpl->currentDesc.Height;
2923 DstRect.left = dstx;
2925 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2926 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2928 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt aswell */
2929 if(trans & DDBLTFAST_SRCCOLORKEY)
2930 Flags |= DDBLT_KEYSRC;
2931 if(trans & DDBLTFAST_DESTCOLORKEY)
2932 Flags |= DDBLT_KEYDEST;
2933 if(trans & DDBLTFAST_WAIT)
2934 Flags |= DDBLT_WAIT;
2935 if(trans & DDBLTFAST_DONOTWAIT)
2936 Flags |= DDBLT_DONOTWAIT;
2938 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2942 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2945 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2946 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2947 TRACE("(%p)->(%p)\n", This, Pal);
2949 *Pal = (IWineD3DPalette *) This->palette;
2953 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2954 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2956 IWineD3DPaletteImpl *pal = This->palette;
2958 TRACE("(%p)\n", This);
2960 if(This->resource.format == WINED3DFMT_P8 ||
2961 This->resource.format == WINED3DFMT_A8P8)
2963 TRACE("Dirtifying surface\n");
2964 This->Flags |= SFLAG_DIRTY;
2967 if(This->Flags & SFLAG_DIBSECTION) {
2968 TRACE("(%p): Updating the hdc's palette\n", This);
2969 for (n=0; n<256; n++) {
2971 col[n].rgbRed = pal->palents[n].peRed;
2972 col[n].rgbGreen = pal->palents[n].peGreen;
2973 col[n].rgbBlue = pal->palents[n].peBlue;
2975 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2976 /* Use the default device palette */
2977 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2978 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2979 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2981 col[n].rgbReserved = 0;
2983 SetDIBColorTable(This->hDC, 0, 256, col);
2989 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2990 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2991 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2992 TRACE("(%p)->(%p)\n", This, Pal);
2994 if(This->palette != NULL)
2995 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2996 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2998 if(PalImpl != NULL) {
2999 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3000 /* Set the device's main palette if the palette
3001 * wasn't a primary palette before
3003 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
3004 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3007 for(i=0; i < 256; i++) {
3008 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3012 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
3015 This->palette = PalImpl;
3017 return IWineD3DSurface_RealizePalette(iface);
3020 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
3021 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3022 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
3024 if ((Flags & DDCKEY_COLORSPACE) != 0) {
3025 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
3026 return DDERR_INVALIDPARAMS;
3029 /* Dirtify the surface, but only if a key was changed */
3031 switch (Flags & ~DDCKEY_COLORSPACE) {
3032 case DDCKEY_DESTBLT:
3033 This->DestBltCKey = *CKey;
3034 This->CKeyFlags |= DDSD_CKDESTBLT;
3037 case DDCKEY_DESTOVERLAY:
3038 This->DestOverlayCKey = *CKey;
3039 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
3042 case DDCKEY_SRCOVERLAY:
3043 This->SrcOverlayCKey = *CKey;
3044 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
3048 This->SrcBltCKey = *CKey;
3049 This->CKeyFlags |= DDSD_CKSRCBLT;
3054 switch (Flags & ~DDCKEY_COLORSPACE) {
3055 case DDCKEY_DESTBLT:
3056 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3059 case DDCKEY_DESTOVERLAY:
3060 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3063 case DDCKEY_SRCOVERLAY:
3064 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3068 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3076 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3077 /** Check against the maximum texture sizes supported by the video card **/
3078 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3080 TRACE("%p\n", This);
3081 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3082 /* one of three options
3083 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)
3084 2: Set the texture to the maxium size (bad idea)
3085 3: WARN and return WINED3DERR_NOTAVAILABLE;
3086 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.
3088 WARN("(%p) Creating an oversized surface\n", This);
3089 This->Flags |= SFLAG_OVERSIZE;
3091 /* This will be initialized on the first blt */
3092 This->glRect.left = 0;
3093 This->glRect.top = 0;
3094 This->glRect.right = 0;
3095 This->glRect.bottom = 0;
3097 /* No oversize, gl rect is the full texture size */
3098 This->Flags &= ~SFLAG_OVERSIZE;
3099 This->glRect.left = 0;
3100 This->glRect.top = 0;
3101 This->glRect.right = This->pow2Width;
3102 This->glRect.bottom = This->pow2Height;
3108 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3109 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3111 TRACE("(%p)\n", This);
3113 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3114 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3115 ie pitch = (width/4) * bytes per block */
3116 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3117 ret = (This->currentDesc.Width >> 2) << 3;
3118 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3119 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3120 ret = (This->currentDesc.Width >> 2) << 4;
3122 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3123 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3124 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3126 ret = This->bytesPerPixel * This->pow2Width;
3129 TRACE("(%p) Returning %ld\n", This, ret);
3133 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3136 IWineD3DSurfaceImpl_QueryInterface,
3137 IWineD3DSurfaceImpl_AddRef,
3138 IWineD3DSurfaceImpl_Release,
3139 /* IWineD3DResource */
3140 IWineD3DSurfaceImpl_GetParent,
3141 IWineD3DSurfaceImpl_GetDevice,
3142 IWineD3DSurfaceImpl_SetPrivateData,
3143 IWineD3DSurfaceImpl_GetPrivateData,
3144 IWineD3DSurfaceImpl_FreePrivateData,
3145 IWineD3DSurfaceImpl_SetPriority,
3146 IWineD3DSurfaceImpl_GetPriority,
3147 IWineD3DSurfaceImpl_PreLoad,
3148 IWineD3DSurfaceImpl_GetType,
3149 /* IWineD3DSurface */
3150 IWineD3DSurfaceImpl_GetContainerParent,
3151 IWineD3DSurfaceImpl_GetContainer,
3152 IWineD3DSurfaceImpl_GetDesc,
3153 IWineD3DSurfaceImpl_LockRect,
3154 IWineD3DSurfaceImpl_UnlockRect,
3155 IWineD3DSurfaceImpl_GetDC,
3156 IWineD3DSurfaceImpl_ReleaseDC,
3157 IWineD3DSurfaceImpl_Flip,
3158 IWineD3DSurfaceImpl_Blt,
3159 IWineD3DSurfaceImpl_GetBltStatus,
3160 IWineD3DSurfaceImpl_GetFlipStatus,
3161 IWineD3DSurfaceImpl_IsLost,
3162 IWineD3DSurfaceImpl_Restore,
3163 IWineD3DSurfaceImpl_BltFast,
3164 IWineD3DSurfaceImpl_GetPalette,
3165 IWineD3DSurfaceImpl_SetPalette,
3166 IWineD3DSurfaceImpl_RealizePalette,
3167 IWineD3DSurfaceImpl_SetColorKey,
3168 IWineD3DSurfaceImpl_GetPitch,
3169 IWineD3DSurfaceImpl_SetMem,
3171 IWineD3DSurfaceImpl_CleanDirtyRect,
3172 IWineD3DSurfaceImpl_AddDirtyRect,
3173 IWineD3DSurfaceImpl_LoadTexture,
3174 IWineD3DSurfaceImpl_SaveSnapshot,
3175 IWineD3DSurfaceImpl_SetContainer,
3176 IWineD3DSurfaceImpl_SetPBufferState,
3177 IWineD3DSurfaceImpl_SetGlTextureDesc,
3178 IWineD3DSurfaceImpl_GetGlDesc,
3179 IWineD3DSurfaceImpl_GetData,
3180 IWineD3DSurfaceImpl_SetFormat,
3181 IWineD3DSurfaceImpl_PrivateSetup