ac9d2621fcc62c9bdd36919ff3e9423773d972eb
[mesa.git] / src / mesa / drivers / d3d / D3DTextureMgr.cpp
1 /*===========================================================================*/
2 /* */
3 /* Mesa-3.0 DirectX 6 Driver */
4 /* */
5 /* By Leigh McRae */
6 /* */
7 /* http://www.altsoftware.com/ */
8 /* */
9 /* Copyright (c) 1999-1998 alt.software inc. All Rights Reserved */
10 /*===========================================================================*/
11 #include "D3DHAL.h"
12 /*===========================================================================*/
13 /* Local function prototypes. */
14 /*===========================================================================*/
15 static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels );
16 static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj );
17 static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject );
18 static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject );
19 HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext );
20 /*===========================================================================*/
21 /* This function will simply set the top of stack to NULL. I only used it */
22 /* just incase I want to add something later. */
23 /*===========================================================================*/
24 /* RETURN: TRUE. */
25 /*===========================================================================*/
26 BOOL InitTMgrHAL( PMESAD3DHAL pHAL )
27 {
28 DPF(( DBG_FUNC, "InitTMgrHAL();" ));
29
30 /* Be clean my friend. */
31 pHAL->pTMList = NULL;
32
33 return TRUE;
34 }
35 /*===========================================================================*/
36 /* This function will walk the Texture Managers linked list and destroy all */
37 /* surfaces (SYSTEM/VIDEO). The texture objects themselves also will be */
38 /* freed. */
39 /* NOTE: this is per/context. */
40 /*===========================================================================*/
41 /* RETURN: */
42 /*===========================================================================*/
43 void TermTMgrHAL( PMESAD3DHAL pHAL )
44 {
45 DPF(( DBG_FUNC, "TermTMgrHAL();" ));
46
47 if ( pHAL && pHAL->pTMList )
48 {
49 /* Destroy the surface and remove the TMO from the stack. */
50 while( DestroyTextureObject(pHAL,NULL) );
51
52 /* Be clean my friend. */
53 pHAL->pTMList = NULL;
54 }
55 }
56 /*===========================================================================*/
57 /* This function is a HACK as I don't know how I can disable a texture with-*/
58 /* out booting it out. Is there know state change? */
59 /*===========================================================================*/
60 /* RETURN: */
61 /*===========================================================================*/
62 extern "C" void DisableTMgrHAL( PMESAD3DSHARED pShared )
63 {
64 PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
65
66 DPF(( DBG_FUNC, "DisableTMgrHAL();" ));
67
68 /* Check too see that we have a valid context. */
69 if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) )
70 {
71 DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" ));
72 return;
73 }
74
75 // TODO: This is a hack to shut off textures.
76 pHAL->lpD3DDevice->SetTexture( 0, NULL );
77 }
78 /*===========================================================================*/
79 /* This function is the only entry into the TextureManager that Mesa/wgl */
80 /* will see. It uses a dwAction to specify what we are doing. I did this as*/
81 /* depending on the cards resources the action taken can change. */
82 /* When this function is called we will always search the Texture Managers */
83 /* linked list (per context remember) and try and find a structure that has */
84 /* the same dwName. If we have a match we pull it out of the list and put it*/
85 /* at the top of the list (TOL). If we don't find one then we create a struc*/
86 /* and put it a TOL. This TOL idea makes for some caching as we will always */
87 /* destroy Texture Surfaces from the bottom up... */
88 /* All texture objects at this point will create a texture surface in System*/
89 /* memory (SMEM). Then we will copy the Mesa texture into the surface using */
90 /* the 'pixel' struc to get the translation info. So now this means that all*/
91 /* textures that Mesa gives me I will have a Surface with a copy. If Mesa */
92 /* changes the texture the I update the surface in (SMEM). */
93 /* Now we have a texture struc and a Texture Surface in SMEM. At this point*/
94 /* we create another surface on the card (VMEM). Finally we blt from the */
95 /* SMEM to the VMEM and set the texture as current. Why do I need two? First*/
96 /* this solves square textures. If the cards CAPS is square textures only */
97 /* then I change the dimensions of the VMEM surface and the blt solves it for*/
98 /* me. Second it saves me from filling D3D textures over and over if the */
99 /* card needs to be creating and destroying surfaces because of low memory. */
100 /* The surface in SMEM is expected to work always. When a surface has to be*/
101 /* created in VMEM then we put it in a loop that tries to create the surface.*/
102 /* If we create the surface ok then we brake from the loop. If we fail then */
103 /* we will call 'FreeTextureMemory' that will return TRUE/FALSE as to whether*/
104 /* memory was freed. If memory was freed then we can try again. If no memory*/
105 /* was freed then it just can't fit. */
106 /* 'FreeTextureMemory' will find the end of the list and start freeing VMEM */
107 /* (never SMEM) surfaces that are not locked. */
108 /* BIND - when we bind and there is a texture struct with a texture surface */
109 /* in VMEM then we just make it current. If we have a struct and a surface */
110 /* in SMEM but no VMEM surface then we create the surface in VMEM and blt */
111 /* from the SMEM surface. If we have nothing its just like a creation... */
112 /*===========================================================================*/
113 /* RETURN: TRUE, FALSE. */
114 /*===========================================================================*/
115 extern "C" BOOL CreateTMgrHAL( PMESAD3DSHARED pShared, DWORD dwName, int level, DWORD dwRequestFlags,
116 RECT *rectDirty, DWORD dwWidth, DWORD dwHeight, DWORD dwAction, void *pPixels )
117 {
118 PMESAD3DHAL pHAL = (PMESAD3DHAL)pShared;
119 PTM_OBJECT pTMObj,
120 pTemp;
121 DDSURFACEDESC2 ddsd2;
122 HRESULT rc;
123
124
125 DPF(( DBG_FUNC, "CreateTMgrHAL();" ));
126
127 DPF(( DBG_TXT_INFO, "Texture:" ));
128 DPF(( DBG_TXT_INFO, "cx: %d cy: %d", dwWidth, dwHeight ));
129 DPF(( DBG_TXT_INFO, "Rect:" ));
130 if ( rectDirty )
131 {
132 DPF(( DBG_TXT_INFO, "x0: %d y0: %d", rectDirty->left, rectDirty->top ));
133 DPF(( DBG_TXT_INFO, "x1: %d y1: %d", rectDirty->right, rectDirty->bottom ));
134 }
135
136 /* Check too see that we have a valid context. */
137 if ( (pHAL == NULL) && (pHAL->lpD3DDevice != NULL) )
138 {
139 DPF(( DBG_TXT_WARN, "Null HAL/Direct3D Device!" ));
140 return FALSE;
141 }
142
143 /*=================================================*/
144 /* See if we can find this texture object by name. */
145 /*=================================================*/
146 for( pTMObj = pHAL->pTMList; pTMObj && (pTMObj->dwName != dwName); pTMObj = pTMObj->next );
147
148 /*=========================================================*/
149 /* Allocate a new object if we didn't get a matching name. */
150 /*=========================================================*/
151 if ( pTMObj == NULL )
152 {
153 pTMObj = (PTM_OBJECT)ALLOC( sizeof(TM_OBJECT) );
154 if ( pTMObj == NULL )
155 return FALSE;
156 memset( pTMObj, 0, sizeof(TM_OBJECT) );
157
158 /* Put the object at the beginning of the list. */
159 pTMObj->next = pHAL->pTMList;
160 if ( pTMObj->next )
161 {
162 pTemp = pTMObj->next;
163 pTemp->prev = pTMObj;
164 }
165 pHAL->pTMList = pTMObj;
166 }
167 else
168 {
169 /*===============================================================*/
170 /* Make some caching happen by pulling this object to the front. */
171 /*===============================================================*/
172 if ( pHAL->pTMList != pTMObj )
173 {
174 /* Pull the object out of the list. */
175 if ( pTMObj->prev )
176 {
177 pTemp = pTMObj->prev;
178 pTemp->next = pTMObj->next;
179 }
180 if ( pTMObj->next )
181 {
182 pTemp = pTMObj->next;
183 pTemp->prev = pTMObj->prev;
184 }
185
186 pTMObj->prev = NULL;
187 pTMObj->next = NULL;
188
189 /* Put the object at the front of the list. */
190 pTMObj->next = pHAL->pTMList;
191 if ( pTMObj->next )
192 {
193 pTemp = pTMObj->next;
194 pTemp->prev = pTMObj;
195 }
196 pHAL->pTMList = pTMObj;
197 }
198 }
199
200 /*========================================================*/
201 /* If we are doing BIND and the texture is in VID memory. */
202 /*========================================================*/
203 if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_Video )
204 {
205 DPF(( DBG_TXT_PROFILE, "Cache HIT (%d)", dwName ));
206
207 /* Make this the current texture. */
208 rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
209 if ( FAILED(rc) )
210 {
211 DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
212 pHAL->lpD3DDevice->SetTexture( 0, NULL );
213 return FALSE;
214 }
215
216 return TRUE;
217 }
218
219 /*=================================================================*/
220 /* If we are doing BIND and the texture is at least in SYS memory. */
221 /*=================================================================*/
222 if ( (dwAction == TM_ACTION_BIND) && pTMObj->lpDDS_System )
223 {
224 DPF(( DBG_TXT_PROFILE, "Cache MISS (%d)", dwName ));
225
226 /* Create the texture on the card. */
227 rc = LoadTextureInVideo( pHAL, pTMObj );
228 if ( rc == FALSE )
229 return FALSE;
230
231 /* Make this the current texture. */
232 rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
233 if ( FAILED(rc) )
234 {
235 DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
236 pHAL->lpD3DDevice->SetTexture( 0, NULL );
237 return FALSE;
238 }
239
240 return TRUE;
241 }
242
243 /*=========================================================*/
244 /* If we are doing UPDATE then try in VID first for speed. */
245 /*=========================================================*/
246 if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_Video &&
247 !(pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY) )
248 {
249 DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" ));
250
251 /* Update the texture on the card. */
252 UpdateTexture( pTMObj, TRUE, rectDirty, (UCHAR *)pPixels );
253
254 /* We updated the texture in VID so kill the SYS so we know its dirty. */
255 if ( pTMObj->lpDDS_System )
256 {
257 DPF(( DBG_TXT_INFO, "Release texture (SYS)" ));
258 DX_RESTORE( pTMObj->lpDDS_System );
259 pTMObj->lpDDS_System->Release();
260 pTMObj->lpDDS_System = NULL;
261 }
262
263 /* Make this the current texture. */
264 rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
265 if ( FAILED(rc) )
266 {
267 DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
268 pHAL->lpD3DDevice->SetTexture( 0, NULL );
269 return FALSE;
270 }
271
272 return TRUE;
273 }
274
275 /*===========================================================*/
276 /* If we are doing UPDATE then try in SYS still gives speed. */
277 /*===========================================================*/
278 if ( (dwAction == TM_ACTION_UPDATE) && pTMObj->lpDDS_System )
279 {
280 DPF(( DBG_TXT_INFO, "Fix the SubTexture update Leigh!" ));
281
282 /* Update the texture in SYS. */
283 UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels );
284
285 /* We updated the SYS texture only so now blt to the VID. */
286 rc = LoadTextureInVideo( pHAL, pTMObj );
287 if ( rc == FALSE )
288 return FALSE;
289
290 /* Make this the current texture. */
291 rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
292 if ( FAILED(rc) )
293 {
294 DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
295 pHAL->lpD3DDevice->SetTexture( 0, NULL );
296 return FALSE;
297 }
298
299 return TRUE;
300 }
301
302 /* At this point we have a valid Texture Manager Object with updated */
303 /* links. We now need to create or update a texture surface that is */
304 /* in system memory. Every texture has a copy in system so we can use*/
305 /* blt to solve problems with textures allocated on the card (square */
306 /* only textures, pixelformats...). */
307
308 // TODO: make support for update also. Dirty rectangle basicly...
309
310 /* Kill the interface if we have one no matter what. */
311 if ( pTMObj->lpD3DTexture2 )
312 {
313 DPF(( DBG_TXT_INFO, "Release Texture2" ));
314 pTMObj->lpD3DTexture2->Release();
315 pTMObj->lpD3DTexture2 = NULL;
316 }
317
318 /* Kill the system surface. TODO: should try to get the SubIMage going again */
319 if ( pTMObj->lpDDS_System )
320 {
321 DPF(( DBG_TXT_INFO, "Release texture (SYS)" ));
322 DX_RESTORE( pTMObj->lpDDS_System );
323 pTMObj->lpDDS_System->Release();
324 pTMObj->lpDDS_System = NULL;
325 }
326
327 /* Kill the Video surface. TODO: need some reuse system... */
328 if ( pTMObj->lpDDS_Video )
329 {
330 DPF(( DBG_TXT_INFO, "Release texture (VID)" ));
331 DX_RESTORE( pTMObj->lpDDS_Video );
332 pTMObj->lpDDS_Video->Release();
333 pTMObj->lpDDS_Video = NULL;
334 }
335
336 /*================================================================*/
337 /* Translate the the Mesa/OpenGL pixel channels to the D3D flags. */
338 /*================================================================*/
339 switch( dwRequestFlags )
340 {
341 case GL_ALPHA:
342 dwRequestFlags = DDPF_ALPHA;
343 DPF(( DBG_TXT_WARN, "GL_ALPHA not supported!)" ));
344 return FALSE;
345
346 case GL_INTENSITY:
347 case GL_LUMINANCE:
348 DPF(( DBG_TXT_WARN, "GL_INTENSITY/GL_LUMINANCE not supported!)" ));
349 dwRequestFlags = DDPF_LUMINANCE;
350 return FALSE;
351
352 case GL_LUMINANCE_ALPHA:
353 DPF(( DBG_TXT_WARN, "GL_LUMINANCE_ALPHA not supported!)" ));
354 dwRequestFlags = DDPF_LUMINANCE | DDPF_ALPHAPIXELS;
355 return FALSE;
356
357 case GL_RGB:
358 DPF(( DBG_TXT_INFO, "Texture -> GL_RGB" ));
359 dwRequestFlags = DDPF_RGB;
360 break;
361
362 case GL_RGBA:
363 DPF(( DBG_TXT_INFO, "Texture -> GL_RGBA" ));
364 dwRequestFlags = DDPF_RGB | DDPF_ALPHAPIXELS;
365 break;
366 }
367
368 /*==============================*/
369 /* Populate the texture object. */
370 /*==============================*/
371 pTMObj->dwName = dwName;
372 pTMObj->lpD3DDevice = pHAL->lpD3DDevice;
373 pTMObj->dwFlags = dwRequestFlags;
374 if ( pHAL->D3DHWDevDesc.dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY )
375 {
376 DPF(( DBG_TXT_INFO, "Convert to Square..." ));
377 pTMObj->dwSHeight = dwHeight;
378 pTMObj->dwSWidth = dwWidth;
379
380 /* Shrink non-square textures. */
381 pTMObj->dwVHeight = (dwHeight > dwWidth) ? dwWidth : dwHeight;
382 pTMObj->dwVWidth = (dwHeight > dwWidth) ? dwWidth : dwHeight;
383 }
384 else
385 {
386 pTMObj->dwSHeight = dwHeight;
387 pTMObj->dwSWidth = dwWidth;
388 pTMObj->dwVHeight = dwHeight;
389 pTMObj->dwVWidth = dwWidth;
390 }
391
392 /*========================*/
393 /* Create SYSTEM surface. */
394 /*========================*/
395
396 /* Request a surface in system memory. */
397 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
398 ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
399 ddsd2.dwWidth = pTMObj->dwSWidth;
400 ddsd2.dwHeight = pTMObj->dwSHeight;
401 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
402 ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_SYSTEMMEMORY;
403 ddsd2.ddsCaps.dwCaps2 = 0L;
404 memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) );
405 ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
406 ddsd2.ddpfPixelFormat.dwFlags = dwRequestFlags;
407 rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat );
408 if ( FAILED(rc) )
409 {
410 RIP( pHAL, "EnumerTextureFormats (SYSTEM)->", ErrorStringD3D(rc) );
411 return FALSE;
412 }
413
414 /* Create the surface using the enumerated pixelformat. */
415 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_System, NULL );
416 if ( FAILED(rc) )
417 {
418 RIP( pHAL, "CreateSurface (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
419 return FALSE;
420 }
421
422 /* Solve the pixel mapping info using the surface pixelformat. */
423 Solve8BitChannelPixelFormat( &ddsd2.ddpfPixelFormat, &pTMObj->pixel );
424
425 /*===================================================================*/
426 /* Fill the texture using the PixelInfo structure to do the mapping. */
427 /*===================================================================*/
428 UpdateTexture( pTMObj, FALSE, NULL, (UCHAR *)pPixels );
429
430 /*=======================*/
431 /* Create VIDEO surface. */
432 /*=======================*/
433 rc = LoadTextureInVideo( pHAL, pTMObj );
434 if ( rc == FALSE )
435 return FALSE;
436
437 /* Make this the current texture. */
438 rc = pHAL->lpD3DDevice->SetTexture( 0, pTMObj->lpD3DTexture2 );
439 if ( FAILED(rc) )
440 {
441 DPF(( DBG_TXT_WARN, "Failed SetTexture() (%s)", ErrorStringD3D(rc) ));
442 pHAL->lpD3DDevice->SetTexture( 0, NULL );
443 return FALSE;
444 }
445
446 return TRUE;
447 }
448 /*===========================================================================*/
449 /* This function will handle the creation and destruction of the texture */
450 /* surfaces on the card. Using the dw'V'Width/Height dimensions the call */
451 /* try and create the texture on the card and keep using FreeTextureMemory */
452 /* until the surace can be created. Once the surface is created we get the */
453 /* interface that we will use to make it the current texture. I didn't put */
454 /* the code to make the texture current in this function as BIND needs to */
455 /* use the same code and this function doesn't always get called when we do a*/
456 /* bind. */
457 /*===========================================================================*/
458 /* RETURN: TRUE, FALSE. */
459 /*===========================================================================*/
460 static BOOL LoadTextureInVideo( PMESAD3DHAL pHAL, PTM_OBJECT pTMObj )
461 {
462 DDSURFACEDESC2 ddsd2;
463 HRESULT rc;
464
465 DPF(( DBG_FUNC, "LoadTextureInVideo();" ));
466
467 /* Kill the interface if we have one no matter what. */
468 if ( pTMObj->lpD3DTexture2 )
469 {
470 DPF(( DBG_TXT_INFO, "Release Texture2" ));
471 pTMObj->lpD3DTexture2->Release();
472 pTMObj->lpD3DTexture2 = NULL;
473 }
474
475 /* Kill the Video surface. TODO: need some reuse system... */
476 if ( pTMObj->lpDDS_Video )
477 {
478 DPF(( DBG_TXT_INFO, "Release texture (VID)" ));
479 DX_RESTORE( pTMObj->lpDDS_Video );
480 pTMObj->lpDDS_Video->Release();
481 pTMObj->lpDDS_Video = NULL;
482 }
483
484 /* Request a surface in Video memory. */
485 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
486 ddsd2.dwSize = sizeof( DDSURFACEDESC2 );
487 ddsd2.dwWidth = pTMObj->dwVWidth;
488 ddsd2.dwHeight = pTMObj->dwVHeight;
489 ddsd2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT;
490 ddsd2.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY;
491 ddsd2.ddsCaps.dwCaps2 = 0L;
492 memset( &ddsd2.ddpfPixelFormat, 0, sizeof(DDPIXELFORMAT) );
493 ddsd2.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
494 ddsd2.ddpfPixelFormat.dwFlags = pTMObj->dwFlags;
495 rc = pHAL->lpD3DDevice->EnumTextureFormats( EnumPFHook, &ddsd2.ddpfPixelFormat );
496 if ( FAILED(rc) )
497 {
498 RIP( pHAL, "EnumerTextureFormats ->", ErrorStringD3D(rc) );
499 return FALSE;
500 }
501
502 /* Make sure we lock so we don't nuke this texture trying to free memory for it. */
503 pTMObj->bLock = TRUE;
504
505 /* Start a loop that will free all textures until we have created the texture */
506 /* surface or we can't free up more memory. */
507 do
508 {
509 /* Try to create the texture surface. */
510 rc = pHAL->lpDD4->CreateSurface( &ddsd2, &pTMObj->lpDDS_Video, NULL );
511 if ( !FAILED(rc) )
512 break;
513
514 DPF(( DBG_TXT_INFO, "Free Texture Memory" ));
515
516 /* DestroyTexture will return TRUE if a surface was freed. */
517 } while( FreeTextureMemory(pHAL,NULL) );
518
519 /* Make sure we unlock or we won't be able to nuke the TMO later. */
520 pTMObj->bLock = FALSE;
521
522 /* Did we create a valid texture surface? */
523 if ( FAILED(rc) )
524 {
525 DPF(( DBG_TXT_WARN, "Failed to load texture" ));
526 pHAL->lpD3DDevice->SetTexture( 0, NULL );
527 return FALSE;
528 }
529
530 DX_RESTORE( pTMObj->lpDDS_System );
531 DX_RESTORE( pTMObj->lpDDS_Video );
532
533 DPF(( DBG_TXT_INFO, "Texture Blt SYSTEM -> VID" ));
534
535 /* Now blt the texture in system memory to the card. */
536 rc = pTMObj->lpDDS_Video->Blt( NULL, pTMObj->lpDDS_System, NULL, DDBLT_WAIT, NULL );
537 if ( FAILED(rc) )
538 {
539 RIP( pHAL, "Blt (TEXTURE) ->", ErrorStringD3D(rc) );
540 return FALSE;
541 }
542
543 /* Get the Texture interface that is used to render with. */
544 pTMObj->lpDDS_Video->QueryInterface( IID_IDirect3DTexture2, (void **)&pTMObj->lpD3DTexture2 );
545 if ( pTMObj->lpD3DTexture2 == NULL )
546 {
547 DPF(( DBG_TXT_WARN, "Failed QueryTextureInterface" ));
548 pHAL->lpD3DDevice->SetTexture( 0, NULL );
549 return FALSE;
550 }
551
552 return TRUE;
553 }
554 /*===========================================================================*/
555 /* If this function gets a texture object struc then we will try and free */
556 /* it. If we get a NULL then we will search from the bottom up and free one */
557 /* VMEM surface. I can only free when the surface isn't locked and of course*/
558 /* there must be a VMEM surface. We never free SMEM surfaces as that isn't */
559 /* the point. */
560 /* TODO: should have a pointer to the bottom of the stack really. */
561 /*===========================================================================*/
562 /* RETURN: */
563 /*===========================================================================*/
564 static BOOL FreeTextureMemory( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject )
565 {
566 PTM_OBJECT pCurrent;
567 BOOL bFreed = FALSE;
568
569 DPF(( DBG_FUNC, "FreeTextureMemory();" ));
570 DPF(( DBG_TXT_WARN, "FREE TEXTURE!" ));
571
572 /* Just to be safe. */
573 if ( !pHAL || !pHAL->pTMList )
574 {
575 DPF(( DBG_TXT_WARN, "FreeTextureMemory() -> NULL pHAL/pHAL->pTMList" ));
576 return FALSE;
577 }
578
579 /* Free the last texture in the list. */
580 if ( pTMObject == NULL )
581 {
582 DPF(( DBG_TXT_INFO, "Free Last texture in cache" ));
583
584 /* Find the last texture object. */
585 for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next );
586
587 /* Now backup until we find a texture on the card. */
588 while( pCurrent && (pCurrent->lpDDS_Video == NULL) && (pCurrent->bLock == FALSE) )
589 pCurrent = pCurrent->prev;
590
591 /* Didn't find anything. */
592 if ( pCurrent == NULL )
593 {
594 DPF(( DBG_TXT_INFO, "No texture memory freed" ));
595 return FALSE;
596 }
597 }
598 else
599 {
600 /* See if we can find this texture object. */
601 for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next );
602
603 /* Didn't find anything. */
604 if ( pCurrent == NULL )
605 {
606 DPF(( DBG_TXT_INFO, "Requested texture to be freed NOT FOUND" ));
607 return FALSE;
608 }
609 }
610
611 /* Can't free this baby. */
612 if ( pCurrent->bLock == TRUE )
613 {
614 DPF(( DBG_TXT_WARN, "Requested texture LOCKED" ));
615 return FALSE;
616 }
617
618 /* Free the texture memory. */
619 if ( pCurrent->lpD3DTexture2 )
620 {
621 DPF(( DBG_TXT_INFO, "Release Texture2" ));
622 pCurrent->lpD3DTexture2->Release();
623 pCurrent->lpD3DTexture2 = NULL;
624 bFreed = TRUE;
625 }
626 if ( pCurrent->lpDDS_Video )
627 {
628 DPF(( DBG_TXT_INFO, "Release texture (VID):" ));
629 DPF(( DBG_TXT_INFO, "dwName: %d", pCurrent->dwName ));
630 DPF(( DBG_TXT_INFO, "cx: %d, cy: %d", pCurrent->dwVWidth, pCurrent->dwVHeight ));
631 pCurrent->lpDDS_Video->Release();
632 pCurrent->lpDDS_Video = NULL;
633 bFreed = TRUE;
634 }
635
636 return bFreed;
637 }
638 /*===========================================================================*/
639 /* This function searches the linked list of texture objects in the supplied*/
640 /* D3Dwrapper structure. If it finds a match it will free it and pull it out*/
641 /* of the linked list. The function works on the bases of a matching pointer*/
642 /* to the object (not matching content). */
643 /* If the function gets passed a NULL then we want to free the last texture */
644 /* object in the list. Used in a loop to destory all. */
645 /*===========================================================================*/
646 /* RETURN: TRUE, FALSE. */
647 /*===========================================================================*/
648 static BOOL DestroyTextureObject( PMESAD3DHAL pHAL, PTM_OBJECT pTMObject )
649 {
650 PTM_OBJECT pCurrent;
651
652 DPF(( DBG_FUNC, "DestoryTextureObject();" ));
653
654 /* Just to be safe. */
655 if ( !pHAL || !pHAL->pTMList )
656 {
657 DPF(( DBG_TXT_WARN, "DestroyTextureObject() -> NULL pHAL/pHAL->pTMList" ));
658 return FALSE;
659 }
660
661 /* Free the last texture in the list. */
662 if ( pTMObject == NULL )
663 {
664 /* Find the last texture object. */
665 for( pCurrent = pHAL->pTMList; pCurrent->next; pCurrent = pCurrent->next );
666 }
667 else
668 {
669 /* See if we can find this texture object. */
670 for( pCurrent = pHAL->pTMList; pCurrent && (pCurrent != pTMObject); pCurrent = pCurrent->next );
671
672 /* Didn't find anything. */
673 if ( pCurrent == NULL )
674 {
675 DPF(( DBG_TXT_WARN, "No textures to be freed" ));
676 return FALSE;
677 }
678 }
679
680 /* Can't free this baby. */
681 if ( pCurrent->bLock == TRUE )
682 {
683 DPF(( DBG_TXT_WARN, "Requested texture to be freed LOCKED" ));
684 return FALSE;
685 }
686
687 /* Free the texture memory. */
688 if ( pCurrent->lpD3DTexture2 )
689 {
690 DPF(( DBG_TXT_INFO, "Release Texture2" ));
691 pCurrent->lpD3DTexture2->Release();
692 pCurrent->lpD3DTexture2 = NULL;
693 }
694 if ( pCurrent->lpDDS_Video )
695 {
696 DPF(( DBG_TXT_INFO, "Release texture (VID):" ));
697 pCurrent->lpDDS_Video->Release();
698 pCurrent->lpDDS_Video = NULL;
699 }
700 if ( pCurrent->lpDDS_System )
701 {
702 DPF(( DBG_TXT_INFO, "Release texture (SYS):" ));
703 pCurrent->lpDDS_System->Release();
704 pCurrent->lpDDS_System = NULL;
705 }
706
707 /* Pull this texture out of the list. */
708 if ( pCurrent == pHAL->pTMList )
709 pHAL->pTMList = NULL;
710 if ( pCurrent->prev )
711 (pCurrent->prev)->next = pCurrent->next;
712 if ( pCurrent->next )
713 (pCurrent->next)->prev = pCurrent->prev;
714 FREE( pCurrent );
715
716 return TRUE;
717 }
718 /*===========================================================================*/
719 /* This function is the callback function that gets called when we are doing*/
720 /* an enumeration of the texture formats supported by this device. The choice*/
721 /* is made by checking to see if we have a match with the supplied D3D pixel-*/
722 /* format. So the enumeration has to pass a desired D3D PF as the user var. */
723 /*===========================================================================*/
724 /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */
725 /*===========================================================================*/
726 static void UpdateTexture( PTM_OBJECT pTMObj, BOOL bVideo, RECT *pRect, UCHAR *pixels )
727 {
728 LPDIRECTDRAWSURFACE4 lpDDS;
729 DDSURFACEDESC2 ddsd2;
730 DWORD srcPitch,
731 dwHeight,
732 dwWidth,
733 dwCol,
734 dwColor;
735 UCHAR *pSrc,
736 *pSrcRow,
737 *pDest,
738 *pDestRow;
739 int rc;
740
741 // TODO: Do I need to pass the h/w when its in the object!
742 DPF(( DBG_FUNC, "UpdateTexture();" ));
743
744 /* Get the surface pointer we are looking for. */
745 lpDDS = (bVideo) ? pTMObj->lpDDS_Video : pTMObj->lpDDS_System;
746
747 /*===================================================================*/
748 /* Fill the texture using the PixelInfo structure to do the mapping. */
749 /*===================================================================*/
750
751 /* Get the surface pointer. */
752 memset( &ddsd2, 0, sizeof(DDSURFACEDESC2) );
753 ddsd2.dwSize = sizeof(DDSURFACEDESC2);
754 rc = lpDDS->Lock( NULL, &ddsd2, DDLOCK_WAIT, NULL );
755 if ( FAILED(rc) )
756 {
757 RIP( NULL, "Lock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
758 return;
759 }
760
761 /* For now we are only updating the system surface so use its dimensions. */
762 dwWidth = (bVideo) ? pTMObj->dwVWidth : pTMObj->dwSWidth;
763 dwHeight = (bVideo) ? pTMObj->dwVHeight : pTMObj->dwSHeight;
764
765 /* If we are updating the whole surface then the pDest/pSrc will */
766 /* always be the same. */
767 if ( pRect == NULL )
768 {
769 pDest = (UCHAR *)ddsd2.lpSurface;
770 pSrc = pixels;
771 }
772
773 /* Fill the texture surface based on the pixelformat flags. */
774 if ( pTMObj->dwFlags == (DDPF_RGB | DDPF_ALPHAPIXELS) )
775 {
776 srcPitch = dwWidth * 4;
777 if ( pRect )
778 {
779 pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
780 pSrc = pixels + (pRect->top * dwWidth * 4) + (pRect->left * 4);
781 dwHeight = (pRect->bottom - pRect->top);
782 dwWidth = (pRect->right - pRect->left);
783 }
784
785 for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
786 {
787 for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
788 {
789 dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
790 dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift );
791 dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift );
792 if ( pTMObj->pixel.aScale == -1.0 )
793 dwColor |= ( (*(pSrc+3) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
794 else
795 dwColor |= ( ((DWORD)(*(pSrc+3) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
796 memcpy( pDest, &dwColor, pTMObj->pixel.cb );
797 pDest += pTMObj->pixel.cb;
798 pSrc += 4;
799 }
800 }
801 }
802 else if ( pTMObj->dwFlags == DDPF_RGB )
803 {
804 srcPitch = dwWidth * 3;
805 if ( pRect )
806 {
807 pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
808 pSrc = pixels + (pRect->top * dwWidth * 3) + (pRect->left * 3);
809 dwHeight = (pRect->bottom - pRect->top);
810 dwWidth = (pRect->right - pRect->left);
811 }
812
813 for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
814 {
815 for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
816 {
817 dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
818 dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.gScale)) << pTMObj->pixel.gShift );
819 dwColor |= ( ((DWORD)(*(pSrc+2) * pTMObj->pixel.bScale)) << pTMObj->pixel.bShift );
820 memcpy( pDest, &dwColor, pTMObj->pixel.cb );
821 pDest += pTMObj->pixel.cb;
822 pSrc += 3;
823 }
824 }
825 }
826 else if ( pTMObj->dwFlags == (DDPF_LUMINANCE | DDPF_ALPHAPIXELS) )
827 {
828 srcPitch = dwWidth * 2;
829 if ( pRect )
830 {
831 pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
832 pSrc = pixels + (pRect->top * dwWidth * 2) + (pRect->left * 2);
833 dwHeight = (pRect->bottom - pRect->top);
834 dwWidth = (pRect->right - pRect->left);
835 }
836
837 for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
838 {
839 for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
840 {
841 dwColor = ( ((DWORD)(*(pSrc ) * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
842 if ( pTMObj->pixel.aScale == -1.0 )
843 dwColor |= ( (*(pSrc+1) & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
844 else
845 dwColor |= ( ((DWORD)(*(pSrc+1) * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
846 memcpy( pDest, &dwColor, pTMObj->pixel.cb );
847 pDest += pTMObj->pixel.cb;
848 pSrc += 2;
849 }
850 }
851 }
852 else if ( pTMObj->dwFlags == DDPF_LUMINANCE )
853 {
854 srcPitch = dwWidth;
855 if ( pRect )
856 {
857 pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
858 pSrc = pixels + (pRect->top * dwWidth) + (pRect->left);
859 dwHeight = (pRect->bottom - pRect->top);
860 dwWidth = (pRect->right - pRect->left);
861 }
862
863 for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
864 {
865 for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
866 {
867 dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.rScale)) << pTMObj->pixel.rShift );
868 memcpy( pDest, &dwColor, pTMObj->pixel.cb );
869 pDest += pTMObj->pixel.cb;
870 pSrc++;
871 }
872 }
873 }
874 else if ( pTMObj->dwFlags == DDPF_ALPHAPIXELS )
875 {
876 srcPitch = dwWidth;
877 if ( pRect )
878 {
879 pDest = ((UCHAR *)ddsd2.lpSurface) + (pRect->top * ddsd2.lPitch) + (pRect->left * pTMObj->pixel.cb);
880 pSrc = pixels + (pRect->top * dwWidth) + (pRect->left);
881 dwHeight = (pRect->bottom - pRect->top);
882 dwWidth = (pRect->right - pRect->left);
883 }
884
885 for( pDestRow = pDest, pSrcRow = pSrc; dwHeight > 0; dwHeight--, pDestRow += ddsd2.lPitch, pSrcRow += srcPitch )
886 {
887 for( dwCol = 0, pDest = pDestRow, pSrc = pSrcRow; dwCol < dwWidth; dwCol++ )
888 {
889 if ( pTMObj->pixel.aScale == -1.0 )
890 dwColor = ( (*pSrc & 0x80) ? (1 << pTMObj->pixel.aShift) : 0 );
891 else
892 dwColor = ( ((DWORD)(*pSrc * pTMObj->pixel.aScale)) << pTMObj->pixel.aShift );
893 memcpy( pDest, &dwColor, pTMObj->pixel.cb );
894 pDest += pTMObj->pixel.cb;
895 pSrc++;
896 }
897 }
898 }
899
900 /* Unlock the surface. */
901 rc = lpDDS->Unlock( NULL );
902 if ( FAILED(rc) )
903 {
904 RIP( NULL, "Unlock (TEXTURE/SYSTEM)->", ErrorStringD3D(rc) );
905 }
906 }
907 /*===========================================================================*/
908 /* This function is the callback function that gets called when we are doing*/
909 /* an enumeration of the texture formats supported by this device. The choice*/
910 /* is made by checking to see if we have a match with the supplied D3D pixel-*/
911 /* format. So the enumeration has to pass a desired D3D PF as the user var. */
912 /*===========================================================================*/
913 /* RETURN: D3DENUMRET_OK, D3DENUMRET_CANCEL. */
914 /*===========================================================================*/
915 HRESULT CALLBACK EnumPFHook( LPDDPIXELFORMAT lpDDPixFmt, LPVOID lpContext )
916 {
917 LPDDPIXELFORMAT lpDDPixFmtRequest = (LPDDPIXELFORMAT)lpContext;
918 PIXELINFO pixel;
919
920 DPF(( DBG_FUNC, "EnumPFHook();" ));
921
922 if ( lpDDPixFmt->dwFlags == lpDDPixFmtRequest->dwFlags )
923 {
924 /* Are we looking for an alpha channel? */
925 if ( lpDDPixFmtRequest->dwFlags & DDPF_ALPHAPIXELS )
926 {
927 /* Try for something that has more then 1bits of Alpha. */
928 Solve8BitChannelPixelFormat( lpDDPixFmt, &pixel );
929 if ( pixel.aScale == -1.0 )
930 {
931 /* Save this format no matter what as its a match of sorts. */
932 memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) );
933 return D3DENUMRET_OK;
934 }
935 }
936
937 /* Save this format as its a good match. */
938 memcpy( lpDDPixFmtRequest, lpDDPixFmt, sizeof(DDPIXELFORMAT) );
939
940 /* We are happy at this point so lets leave. */
941 return D3DENUMRET_CANCEL;
942 }
943
944 return D3DENUMRET_OK;
945 }
946
947