1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      DirectX implementation of some of the primitive routines.
12  *
13  *
14  *      By Pavel Sountsov.
15  *
16  *      See readme.txt for copyright information.
17  */
18 
19 #include "allegro5/allegro.h"
20 #include "allegro5/allegro_primitives.h"
21 #include "allegro5/internal/aintern_bitmap.h"
22 #include "allegro5/internal/aintern_prim_directx.h"
23 #include "allegro5/internal/aintern_prim_soft.h"
24 #include "allegro5/internal/aintern_prim.h"
25 #include "allegro5/internal/aintern_display.h"
26 
27 #include "allegro5/platform/alplatf.h"
28 
29 #ifdef ALLEGRO_CFG_D3D
30 
31 #include "allegro5/allegro_direct3d.h"
32 #include "allegro5/internal/aintern_direct3d.h"
33 
34 ALLEGRO_DEBUG_CHANNEL("d3d_primitives")
35 
36 static ALLEGRO_MUTEX *d3d_mutex;
37 /*
38  * In the context of this file, legacy cards pretty much refer to older Intel cards.
39  * They are distinguished by three misfeatures:
40  * 1. They don't support shaders
41  * 2. They don't support custom vertices
42  * 3. DrawIndexedPrimitiveUP is broken
43  *
44  * Since shaders are used 100% of the time, this means that for these cards
45  * the incoming vertices are first converted into the vertex type that these cards
46  * can handle.
47  */
48 static bool legacy_card = false;
49 static bool know_card_type = false;
50 
is_legacy_card(void)51 static bool is_legacy_card(void)
52 {
53    if (!know_card_type) {
54       ALLEGRO_CONFIG* sys_cfg = al_get_system_config();
55       const char* detection_setting = al_get_config_value(sys_cfg, "graphics", "prim_d3d_legacy_detection");
56       detection_setting = detection_setting ? detection_setting : "default";
57       if (strcmp(detection_setting, "default") == 0) {
58          D3DCAPS9 caps;
59          LPDIRECT3DDEVICE9 device = al_get_d3d_device(al_get_current_display());
60          device->GetDeviceCaps(&caps);
61          if (caps.PixelShaderVersion < D3DPS_VERSION(2, 0))
62             legacy_card = true;
63       } else if(strcmp(detection_setting, "force_legacy") == 0) {
64          legacy_card = true;
65       } else if(strcmp(detection_setting, "force_modern") == 0) {
66           legacy_card = false;
67       } else {
68          ALLEGRO_WARN("Invalid setting for prim_d3d_legacy_detection.\n");
69          legacy_card = false;
70       }
71       if (legacy_card) {
72          ALLEGRO_WARN("Your GPU is considered legacy! Some of the features of the primitives addon will be slower/disabled.\n");
73       }
74       know_card_type = true;
75    }
76    return legacy_card;
77 }
78 
79 typedef struct LEGACY_VERTEX
80 {
81    float x, y, z;
82    DWORD color;
83    float u, v;
84 } LEGACY_VERTEX;
85 
86 static uint8_t* legacy_buffer;
87 static size_t legacy_buffer_size = 0;
88 #define A5V_FVF (D3DFVF_XYZ | D3DFVF_TEX2 | D3DFVF_TEXCOORDSIZE2(0) | D3DFVF_TEXCOORDSIZE4(1))
89 #define A5V_LEGACY_FVF (D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1)
90 
91 typedef struct DISPLAY_LOCAL_DATA
92 {
93    LPDIRECT3DDEVICE9 device;
94    LPDIRECT3DVERTEXSHADER9 shader;
95    ALLEGRO_INDEX_BUFFER* loop_index_buffer;
96 } DISPLAY_LOCAL_DATA;
97 
98 static DISPLAY_LOCAL_DATA* display_local_data;
99 static int display_local_data_size = 0;
100 
display_invalidated(ALLEGRO_DISPLAY * display)101 static void display_invalidated(ALLEGRO_DISPLAY* display)
102 {
103    int ii;
104    LPDIRECT3DDEVICE9 device = al_get_d3d_device(display);
105    /*
106     * If there is no mutex, the addon has been shutdown earlier
107     */
108    if(!d3d_mutex)
109       return;
110 
111    al_lock_mutex(d3d_mutex);
112 
113    for(ii = 0; ii < display_local_data_size; ii++)
114    {
115       if(display_local_data[ii].device == device) {
116          display_local_data[ii].shader->Release();
117          display_local_data[ii] = display_local_data[display_local_data_size - 1];
118          display_local_data_size--;
119          break;
120       }
121    }
122 
123    al_unlock_mutex(d3d_mutex);
124 }
125 
get_display_local_data(ALLEGRO_DISPLAY * display)126 static DISPLAY_LOCAL_DATA get_display_local_data(ALLEGRO_DISPLAY* display)
127 {
128    LPDIRECT3DDEVICE9 device = al_get_d3d_device(display);
129    DISPLAY_LOCAL_DATA ret;
130    bool create_new = false;
131 
132    /*
133     * Lock the mutex so that the entries are not messed up by a
134     * display blowing up/being created
135     */
136    al_lock_mutex(d3d_mutex);
137 
138    if (display_local_data_size == 0) {
139       display_local_data = (DISPLAY_LOCAL_DATA*)al_malloc(sizeof(DISPLAY_LOCAL_DATA));
140       display_local_data_size = 1;
141       create_new = true;
142    }
143    else if (display_local_data[0].device != device) {
144       int ii;
145       bool found = false;
146       for(ii = 1; ii < display_local_data_size; ii++)
147       {
148          if(display_local_data[ii].device == device) {
149             /*
150              * Move this entry to the front, so the search goes faster
151              * next time - presumably the al_draw_prim will be called
152              * several times for each display before switching again
153              */
154             DISPLAY_LOCAL_DATA t = display_local_data[0];
155             display_local_data[0] = display_local_data[ii];
156             display_local_data[ii] = t;
157 
158             found = true;
159 
160             break;
161          }
162       }
163 
164       if (!found) {
165          DISPLAY_LOCAL_DATA t = display_local_data[0];
166 
167          display_local_data_size++;
168          display_local_data = (DISPLAY_LOCAL_DATA *)al_realloc(display_local_data, sizeof(DISPLAY_LOCAL_DATA) * display_local_data_size);
169 
170          display_local_data[display_local_data_size - 1] = t;
171          create_new = true;
172       }
173    }
174 
175    if (create_new) {
176       int initial_indices[2] = {0, 0};
177       display_local_data[0].device = device;
178       display_local_data[0].shader = (LPDIRECT3DVERTEXSHADER9)_al_create_default_primitives_shader(device);
179       display_local_data[0].loop_index_buffer = al_create_index_buffer(sizeof(int), initial_indices, 2, 0);
180 
181       _al_add_display_invalidated_callback(display, &display_invalidated);
182    }
183 
184    ret = display_local_data[0];
185 
186    al_unlock_mutex(d3d_mutex);
187 
188    return ret;
189 }
190 
destroy_display_local_data(void)191 static void destroy_display_local_data(void)
192 {
193    int ii;
194    for(ii = 0; ii < display_local_data_size; ii++)
195    {
196       display_local_data[ii].shader->Release();
197       al_destroy_index_buffer(display_local_data[ii].loop_index_buffer);
198    }
199    display_local_data_size = 0;
200    al_free(display_local_data);
201    display_local_data = NULL;
202 }
203 
204 #endif
205 
_al_init_d3d_driver(void)206 bool _al_init_d3d_driver(void)
207 {
208    #ifdef ALLEGRO_CFG_D3D
209    d3d_mutex = al_create_mutex();
210    #endif
211    return true;
212 }
213 
_al_shutdown_d3d_driver(void)214 void _al_shutdown_d3d_driver(void)
215 {
216    #ifdef ALLEGRO_CFG_D3D
217    al_destroy_mutex(d3d_mutex);
218    al_free(legacy_buffer);
219    d3d_mutex = NULL;
220    legacy_buffer = NULL;
221 
222    destroy_display_local_data();
223 
224    legacy_card = false;
225    know_card_type = false;
226    legacy_buffer_size = 0;
227    #endif
228 }
229 
230 #ifdef ALLEGRO_CFG_D3D
231 
convert_to_legacy_vertices(const void * vtxs,int num_vertices,const int * indices,bool loop,bool pp)232 static void* convert_to_legacy_vertices(const void* vtxs, int num_vertices, const int* indices, bool loop, bool pp)
233 {
234    const ALLEGRO_VERTEX* vtx = (const ALLEGRO_VERTEX *)vtxs;
235    int ii;
236    int num_needed_vertices = num_vertices;
237    size_t needed_size;
238 
239    if (pp && !indices && !loop) {
240       return (void *)vtxs;
241    }
242 
243    if(loop)
244       num_needed_vertices++;
245 
246    needed_size = num_needed_vertices * (pp ? sizeof(ALLEGRO_VERTEX) : sizeof(LEGACY_VERTEX));
247 
248    if(legacy_buffer == 0) {
249       legacy_buffer = (uint8_t *)al_malloc(needed_size);
250       legacy_buffer_size = needed_size;
251    } else if (needed_size > legacy_buffer_size) {
252       size_t new_size = needed_size * 1.5;
253       legacy_buffer = (uint8_t *)al_realloc(legacy_buffer, new_size);
254       legacy_buffer_size = new_size;
255    }
256 
257    if (pp) {
258       ALLEGRO_VERTEX *buffer = (ALLEGRO_VERTEX *)legacy_buffer;
259       for(ii = 0; ii < num_vertices; ii++) {
260          if(indices)
261             buffer[ii] = vtx[indices[ii]];
262          else
263             buffer[ii] = vtx[ii];
264       }
265       if(loop)
266          buffer[num_vertices] = buffer[0];
267    }
268    else {
269       LEGACY_VERTEX *buffer = (LEGACY_VERTEX *)legacy_buffer;
270       for(ii = 0; ii < num_vertices; ii++) {
271          ALLEGRO_VERTEX vertex;
272 
273          if(indices)
274             vertex = vtx[indices[ii]];
275          else
276             vertex = vtx[ii];
277 
278          buffer[ii].x = vertex.x;
279          buffer[ii].y = vertex.y;
280          buffer[ii].z = vertex.z;
281 
282          buffer[ii].u = vertex.u;
283          buffer[ii].v = vertex.v;
284 
285          buffer[ii].color = D3DCOLOR_COLORVALUE(vertex.color.r, vertex.color.g, vertex.color.b, vertex.color.a);
286       }
287       if(loop)
288          buffer[num_vertices] = buffer[0];
289    }
290 
291    return legacy_buffer;
292 }
293 
294 struct D3D_STATE
295 {
296    DWORD old_wrap_state[2];
297    DWORD old_ttf_state;
298    IDirect3DVertexShader9* old_vtx_shader;
299 };
300 
setup_state(LPDIRECT3DDEVICE9 device,const ALLEGRO_VERTEX_DECL * decl,ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,DISPLAY_LOCAL_DATA data)301 static D3D_STATE setup_state(LPDIRECT3DDEVICE9 device, const ALLEGRO_VERTEX_DECL* decl, ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, DISPLAY_LOCAL_DATA data)
302 {
303    D3D_STATE state;
304    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
305    ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp;
306 
307    if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
308       IDirect3DPixelShader9* old_pix_shader;
309       device->GetVertexShader(&state.old_vtx_shader);
310       device->GetPixelShader(&old_pix_shader);
311 
312       if(!old_pix_shader) {
313          _al_d3d_set_blender(d3d_disp);
314       }
315 
316       if(!state.old_vtx_shader) {
317          /* Prepare the default shader */
318          if(!is_legacy_card()) {
319             if(decl)
320                _al_setup_primitives_shader(device, decl);
321             else
322                _al_setup_default_primitives_shader(device, data.shader);
323          }
324       }
325    }
326    else {
327       state.old_vtx_shader = NULL;
328       _al_d3d_set_blender(d3d_disp);
329    }
330 
331    /* Set the vertex declarations */
332    if(is_legacy_card() && !(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
333       device->SetFVF(A5V_LEGACY_FVF);
334    } else {
335       if(decl) {
336          device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)decl->d3d_decl);
337       } else {
338          device->SetFVF(A5V_FVF);
339       }
340    }
341 
342    if(!state.old_vtx_shader || (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
343       /* Set up the texture */
344       if (texture) {
345          LPDIRECT3DTEXTURE9 d3d_texture;
346          int tex_x, tex_y;
347          D3DSURFACE_DESC desc;
348          float mat[4][4] = {
349             {1, 0, 0, 0},
350             {0, 1, 0, 0},
351             {0, 0, 1, 0},
352             {0, 0, 0, 1}
353          };
354 
355          d3d_texture = al_get_d3d_video_texture(texture);
356 
357          d3d_texture->GetLevelDesc(0, &desc);
358          al_get_d3d_texture_position(texture, &tex_x, &tex_y);
359 
360          if(decl) {
361             if(decl->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL].attribute) {
362                mat[0][0] = 1.0f / desc.Width;
363                mat[1][1] = 1.0f / desc.Height;
364             } else {
365                mat[0][0] = (float)al_get_bitmap_width(texture) / desc.Width;
366                mat[1][1] = (float)al_get_bitmap_height(texture) / desc.Height;
367             }
368          } else {
369             mat[0][0] = 1.0f / desc.Width;
370             mat[1][1] = 1.0f / desc.Height;
371          }
372          mat[2][0] = (float)tex_x / desc.Width;
373          mat[2][1] = (float)tex_y / desc.Height;
374 
375 
376          if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
377 #ifdef ALLEGRO_CFG_SHADER_HLSL
378             d3d_disp->effect->SetMatrix(ALLEGRO_SHADER_VAR_TEX_MATRIX, (D3DXMATRIX *)mat);
379             d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX_MATRIX, true);
380             d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, true);
381             d3d_disp->effect->SetTexture(ALLEGRO_SHADER_VAR_TEX, d3d_texture);
382 #endif
383          }
384          else {
385             if(is_legacy_card()) {
386                device->GetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, &state.old_ttf_state);
387                device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_COUNT2);
388                device->SetTransform(D3DTS_TEXTURE0, (D3DMATRIX *)&mat);
389             } else {
390                _al_set_texture_matrix(device, mat[0]);
391             }
392          }
393 
394          device->SetTexture(0, d3d_texture);
395 
396       } else {
397          /* Don't unbind the texture here if shaders are used, since the user may
398           * have set the 0'th texture unit manually via the shader API. */
399          if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
400             device->SetTexture(0, NULL);
401          }
402       }
403    }
404 
405    device->GetSamplerState(0, D3DSAMP_ADDRESSU, &state.old_wrap_state[0]);
406    device->GetSamplerState(0, D3DSAMP_ADDRESSV, &state.old_wrap_state[1]);
407 
408    device->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
409    device->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
410 
411    if (texture) {
412       int texture_flags = al_get_bitmap_flags(texture);
413       if (texture_flags & ALLEGRO_MIN_LINEAR) {
414          device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
415       }
416       else {
417          device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
418       }
419       if (texture_flags & ALLEGRO_MAG_LINEAR) {
420          device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
421       }
422       else {
423          device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
424       }
425       if (texture_flags & ALLEGRO_MIPMAP) {
426          device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
427       }
428       else {
429          device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);
430       }
431    }
432 
433    return state;
434 }
435 
revert_state(D3D_STATE state,LPDIRECT3DDEVICE9 device,ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture)436 static void revert_state(D3D_STATE state, LPDIRECT3DDEVICE9 device, ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture)
437 {
438    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
439    ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp;
440    (void)d3d_disp;
441 #ifdef ALLEGRO_CFG_SHADER_HLSL
442    if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
443       d3d_disp->effect->End();
444       d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX_MATRIX, false);
445       d3d_disp->effect->SetBool(ALLEGRO_SHADER_VAR_USE_TEX, false);
446    }
447 #endif
448 
449    device->SetSamplerState(0, D3DSAMP_ADDRESSU, state.old_wrap_state[0]);
450    device->SetSamplerState(0, D3DSAMP_ADDRESSV, state.old_wrap_state[1]);
451 
452    if(!state.old_vtx_shader && is_legacy_card() && texture) {
453       device->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, state.old_ttf_state);
454    }
455 
456    if (!(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
457       if(!state.old_vtx_shader)
458          device->SetVertexShader(0);
459    }
460 }
461 
draw_prim_raw(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,const void * vtx,const ALLEGRO_VERTEX_DECL * decl,const int * indices,int num_vtx,int type)462 static int draw_prim_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture,
463    const void* vtx, const ALLEGRO_VERTEX_DECL* decl,
464    const int* indices, int num_vtx, int type)
465 {
466    int stride;
467    int num_primitives = 0;
468    LPDIRECT3DDEVICE9 device;
469    int min_idx = 0, max_idx = num_vtx - 1;
470    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
471    ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp;
472    UINT required_passes = 1;
473    unsigned int i;
474    D3D_STATE state;
475    DISPLAY_LOCAL_DATA data;
476    (void)d3d_disp;
477 
478    if (al_is_d3d_device_lost(disp)) {
479       return 0;
480    }
481 
482    if (is_legacy_card() && !(disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE)) {
483       stride = (int)sizeof(LEGACY_VERTEX);
484    }
485    else {
486       stride = (decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX));
487    }
488 
489    /* Check for early exit */
490    if((is_legacy_card() && decl) || (decl && decl->d3d_decl == 0)) {
491       if(!indices)
492          return _al_draw_prim_soft(texture, vtx, decl, 0, num_vtx, type);
493       else
494          return _al_draw_prim_indexed_soft(texture, vtx, decl, indices, num_vtx, type);
495    }
496 
497    int num_idx = num_vtx;
498    if(indices)
499    {
500       int ii;
501       for(ii = 0; ii < num_vtx; ii++)
502       {
503          int idx = indices[ii];
504          if(ii == 0) {
505             min_idx = idx;
506             max_idx = idx;
507          } else if (idx < min_idx) {
508             min_idx = idx;
509          } else if (idx > max_idx) {
510             max_idx = idx;
511          }
512       }
513       num_idx = max_idx + 1 - min_idx;
514    }
515 
516    device = al_get_d3d_device(disp);
517 
518    data = get_display_local_data(disp);
519 
520    state = setup_state(device, decl, target, texture, data);
521 
522    /* Convert vertices for legacy cards */
523    if(is_legacy_card()) {
524       al_lock_mutex(d3d_mutex);
525       vtx = convert_to_legacy_vertices(vtx, num_vtx, indices, type == ALLEGRO_PRIM_LINE_LOOP,
526          disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE);
527    }
528 
529 #ifdef ALLEGRO_CFG_SHADER_HLSL
530    if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
531       d3d_disp->effect->Begin(&required_passes, 0);
532    }
533 #endif
534 
535    for (i = 0; i < required_passes; i++) {
536 #ifdef ALLEGRO_CFG_SHADER_HLSL
537       if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
538          d3d_disp->effect->BeginPass(i);
539       }
540 #endif
541 
542       if (!indices || is_legacy_card())
543       {
544          switch (type) {
545             case ALLEGRO_PRIM_LINE_LIST: {
546                num_primitives = num_vtx / 2;
547                device->DrawPrimitiveUP(D3DPT_LINELIST, num_primitives, vtx, stride);
548                break;
549             };
550             case ALLEGRO_PRIM_LINE_STRIP: {
551                num_primitives = num_vtx - 1;
552                device->DrawPrimitiveUP(D3DPT_LINESTRIP, num_primitives, vtx, stride);
553                break;
554             };
555             case ALLEGRO_PRIM_LINE_LOOP: {
556                num_primitives = num_vtx - 1;
557                device->DrawPrimitiveUP(D3DPT_LINESTRIP, num_primitives, vtx, stride);
558                if(!is_legacy_card()) {
559                   int in[2];
560                   in[0] = 0;
561                   in[1] = num_vtx-1;
562 
563                   device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, 0, num_vtx, 1, in, D3DFMT_INDEX32, vtx, stride);
564                } else {
565                   device->DrawPrimitiveUP(D3DPT_LINELIST, 1, (char*)vtx + stride * (num_vtx - 1), stride);
566                }
567                break;
568             };
569             case ALLEGRO_PRIM_TRIANGLE_LIST: {
570                num_primitives = num_vtx / 3;
571                device->DrawPrimitiveUP(D3DPT_TRIANGLELIST, num_primitives, vtx, stride);
572                break;
573             };
574             case ALLEGRO_PRIM_TRIANGLE_STRIP: {
575                num_primitives = num_vtx - 2;
576                device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, num_primitives, vtx, stride);
577                break;
578             };
579             case ALLEGRO_PRIM_TRIANGLE_FAN: {
580                num_primitives = num_vtx - 2;
581                device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, num_primitives, vtx, stride);
582                break;
583             };
584             case ALLEGRO_PRIM_POINT_LIST: {
585                num_primitives = num_vtx;
586                device->DrawPrimitiveUP(D3DPT_POINTLIST, num_primitives, vtx, stride);
587                break;
588             };
589          }
590       } else {
591          switch (type) {
592             case ALLEGRO_PRIM_LINE_LIST: {
593                num_primitives = num_vtx / 2;
594                device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
595                break;
596             };
597             case ALLEGRO_PRIM_LINE_STRIP: {
598                num_primitives = num_vtx - 1;
599                device->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
600                break;
601             };
602             case ALLEGRO_PRIM_LINE_LOOP: {
603                int in[2];
604                num_primitives = num_vtx - 1;
605                device->DrawIndexedPrimitiveUP(D3DPT_LINESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
606 
607                in[0] = indices[0];
608                in[1] = indices[num_vtx-1];
609                min_idx = in[0] > in[1] ? in[1] : in[0];
610                max_idx = in[0] > in[1] ? in[0] : in[1];
611                num_idx = max_idx - min_idx + 1;
612                device->DrawIndexedPrimitiveUP(D3DPT_LINELIST, min_idx, num_idx, 1, in, D3DFMT_INDEX32, vtx, stride);
613                break;
614             };
615             case ALLEGRO_PRIM_TRIANGLE_LIST: {
616                num_primitives = num_vtx / 3;
617                device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
618                break;
619             };
620             case ALLEGRO_PRIM_TRIANGLE_STRIP: {
621                num_primitives = num_vtx - 2;
622                device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLESTRIP, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
623                break;
624             };
625             case ALLEGRO_PRIM_TRIANGLE_FAN: {
626                num_primitives = num_vtx - 2;
627                device->DrawIndexedPrimitiveUP(D3DPT_TRIANGLEFAN, min_idx, num_idx, num_primitives, indices, D3DFMT_INDEX32, vtx, stride);
628                break;
629             };
630             case ALLEGRO_PRIM_POINT_LIST: {
631                /*
632                 * D3D does not support point lists in indexed mode, so we draw them using the non-indexed mode. To gain at least a semblance
633                 * of speed, we detect consecutive runs of vertices and draw them using a single DrawPrimitiveUP call
634                 */
635                int ii = 0;
636                int start_idx = indices[0];
637                int run_length = 0;
638                for(ii = 0; ii < num_vtx; ii++)
639                {
640                   run_length++;
641                   if(indices[ii] + 1 != indices[ii + 1] || ii == num_vtx - 1) {
642                      device->DrawPrimitiveUP(D3DPT_POINTLIST, run_length, (const char*)vtx + start_idx * stride, stride);
643                      if(ii != num_vtx - 1)
644                         start_idx = indices[ii + 1];
645                      run_length = 0;
646                   }
647                }
648                break;
649             };
650          }
651       }
652 
653 #ifdef ALLEGRO_CFG_SHADER_HLSL
654       if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
655          d3d_disp->effect->EndPass();
656       }
657 #endif
658    }
659 
660    if(is_legacy_card())
661       al_unlock_mutex(d3d_mutex);
662 
663    revert_state(state, device, target, texture);
664 
665    return num_primitives;
666 }
667 
668 #endif
669 
_al_draw_prim_directx(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,const void * vtxs,const ALLEGRO_VERTEX_DECL * decl,int start,int end,int type)670 int _al_draw_prim_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, int start, int end, int type)
671 {
672 #ifdef ALLEGRO_CFG_D3D
673    int stride = decl ? decl->stride : (int)sizeof(ALLEGRO_VERTEX);
674    return draw_prim_raw(target, texture, (const char*)vtxs + start * stride, decl, 0, end - start, type);
675 #else
676    (void)target;
677    (void)texture;
678    (void)vtxs;
679    (void)start;
680    (void)end;
681    (void)type;
682    (void)decl;
683 
684    return 0;
685 #endif
686 }
687 
_al_draw_prim_indexed_directx(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,const void * vtxs,const ALLEGRO_VERTEX_DECL * decl,const int * indices,int num_vtx,int type)688 int _al_draw_prim_indexed_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, const void* vtxs, const ALLEGRO_VERTEX_DECL* decl, const int* indices, int num_vtx, int type)
689 {
690 #ifdef ALLEGRO_CFG_D3D
691    return draw_prim_raw(target, texture, vtxs, decl, indices, num_vtx, type);
692 #else
693    (void)target;
694    (void)texture;
695    (void)vtxs;
696    (void)indices;
697    (void)num_vtx;
698    (void)type;
699    (void)decl;
700 
701    return 0;
702 #endif
703 }
704 
705 #ifdef ALLEGRO_CFG_D3D
draw_buffer_raw(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,ALLEGRO_INDEX_BUFFER * index_buffer,int start,int end,int type)706 static int draw_buffer_raw(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type)
707 {
708    int num_primitives = 0;
709    int num_vtx = end - start;
710    LPDIRECT3DDEVICE9 device;
711    ALLEGRO_DISPLAY *disp = _al_get_bitmap_display(target);
712    ALLEGRO_DISPLAY_D3D *d3d_disp = (ALLEGRO_DISPLAY_D3D *)disp;
713    UINT required_passes = 1;
714    unsigned int i;
715    D3D_STATE state;
716    DISPLAY_LOCAL_DATA data;
717    (void)d3d_disp;
718 
719    if (al_is_d3d_device_lost(disp)) {
720       return 0;
721    }
722 
723    /* Check for early exit for legacy cards */
724    if (vertex_buffer->decl && vertex_buffer->decl->d3d_decl == 0) {
725       return _al_draw_buffer_common_soft(vertex_buffer, texture, index_buffer, start, end, type);
726    }
727 
728    device = al_get_d3d_device(disp);
729 
730    data = get_display_local_data(disp);
731 
732    state = setup_state(device, vertex_buffer->decl, target, texture, data);
733 
734    device->SetStreamSource(0, (IDirect3DVertexBuffer9*)vertex_buffer->common.handle, 0, vertex_buffer->decl ? vertex_buffer->decl->stride : (int)sizeof(ALLEGRO_VERTEX));
735 
736    if (index_buffer) {
737       device->SetIndices((IDirect3DIndexBuffer9*)index_buffer->common.handle);
738    }
739 
740 #ifdef ALLEGRO_CFG_SHADER_HLSL
741    if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
742       d3d_disp->effect->Begin(&required_passes, 0);
743    }
744 #endif
745 
746    for (i = 0; i < required_passes; i++) {
747 #ifdef ALLEGRO_CFG_SHADER_HLSL
748       if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
749          d3d_disp->effect->BeginPass(i);
750       }
751 #endif
752 
753       if (!index_buffer) {
754          switch (type) {
755             case ALLEGRO_PRIM_LINE_LIST: {
756                num_primitives = num_vtx / 2;
757                device->DrawPrimitive(D3DPT_LINELIST, start, num_primitives);
758                break;
759             };
760             case ALLEGRO_PRIM_LINE_STRIP: {
761                num_primitives = num_vtx - 1;
762                device->DrawPrimitive(D3DPT_LINESTRIP, start, num_primitives);
763                break;
764             };
765             case ALLEGRO_PRIM_LINE_LOOP: {
766                int* indices;
767                num_primitives = num_vtx - 1;
768                device->DrawPrimitive(D3DPT_LINESTRIP, start, num_primitives);
769 
770                if (data.loop_index_buffer) {
771                   al_lock_mutex(d3d_mutex);
772                   indices = (int*)al_lock_index_buffer(data.loop_index_buffer, 0, 2, ALLEGRO_LOCK_WRITEONLY);
773                   ASSERT(indices);
774                   indices[0] = start;
775                   indices[1] = start + num_vtx - 1;
776                   al_unlock_index_buffer(data.loop_index_buffer);
777                   device->SetIndices((IDirect3DIndexBuffer9*)data.loop_index_buffer->common.handle);
778                   device->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, al_get_vertex_buffer_size(vertex_buffer), 0, 1);
779                   al_unlock_mutex(d3d_mutex);
780                }
781                break;
782             };
783             case ALLEGRO_PRIM_TRIANGLE_LIST: {
784                num_primitives = num_vtx / 3;
785                device->DrawPrimitive(D3DPT_TRIANGLELIST, start, num_primitives);
786                break;
787             };
788             case ALLEGRO_PRIM_TRIANGLE_STRIP: {
789                num_primitives = num_vtx - 2;
790                device->DrawPrimitive(D3DPT_TRIANGLESTRIP, start, num_primitives);
791                break;
792             };
793             case ALLEGRO_PRIM_TRIANGLE_FAN: {
794                num_primitives = num_vtx - 2;
795                device->DrawPrimitive(D3DPT_TRIANGLEFAN, start, num_primitives);
796                break;
797             };
798             case ALLEGRO_PRIM_POINT_LIST: {
799                num_primitives = num_vtx;
800                device->DrawPrimitive(D3DPT_POINTLIST, start, num_primitives);
801                break;
802             };
803          }
804       }
805       else {
806          int vbuff_size = al_get_vertex_buffer_size(vertex_buffer);
807          switch (type) {
808             case ALLEGRO_PRIM_LINE_LIST: {
809                num_primitives = num_vtx / 2;
810                device->DrawIndexedPrimitive(D3DPT_LINELIST, 0, 0, vbuff_size, start, num_primitives);
811                break;
812             };
813             case ALLEGRO_PRIM_LINE_STRIP: {
814                num_primitives = num_vtx - 1;
815                device->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, 0, vbuff_size, start, num_primitives);
816                break;
817             };
818             case ALLEGRO_PRIM_LINE_LOOP: {
819                /* Unimplemented, too hard to do in a consistent fashion. */
820                break;
821             };
822             case ALLEGRO_PRIM_TRIANGLE_LIST: {
823                num_primitives = num_vtx / 3;
824                device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, vbuff_size, start, num_primitives);
825                break;
826             };
827             case ALLEGRO_PRIM_TRIANGLE_STRIP: {
828                num_primitives = num_vtx - 2;
829                device->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, vbuff_size, start, num_primitives);
830                break;
831             };
832             case ALLEGRO_PRIM_TRIANGLE_FAN: {
833                num_primitives = num_vtx - 2;
834                device->DrawIndexedPrimitive(D3DPT_TRIANGLEFAN, 0, 0, vbuff_size, start, num_primitives);
835                break;
836             };
837             case ALLEGRO_PRIM_POINT_LIST: {
838                /* Unimplemented, too hard to do in a consistent fashion. */
839                break;
840             };
841          }
842       }
843 
844 #ifdef ALLEGRO_CFG_SHADER_HLSL
845       if (disp->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
846          d3d_disp->effect->EndPass();
847       }
848 #endif
849    }
850 
851    if (is_legacy_card())
852       al_unlock_mutex(d3d_mutex);
853 
854    revert_state(state, device, target, texture);
855 
856    return num_primitives;
857 }
858 #endif
859 
_al_draw_vertex_buffer_directx(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,int start,int end,int type)860 int _al_draw_vertex_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, int start, int end, int type)
861 {
862 #ifdef ALLEGRO_CFG_D3D
863    return draw_buffer_raw(target, texture, vertex_buffer, NULL, start, end, type);
864 #else
865    (void)target;
866    (void)texture;
867    (void)vertex_buffer;
868    (void)start;
869    (void)end;
870    (void)type;
871 
872    return 0;
873 #endif
874 }
875 
_al_draw_indexed_buffer_directx(ALLEGRO_BITMAP * target,ALLEGRO_BITMAP * texture,ALLEGRO_VERTEX_BUFFER * vertex_buffer,ALLEGRO_INDEX_BUFFER * index_buffer,int start,int end,int type)876 int _al_draw_indexed_buffer_directx(ALLEGRO_BITMAP* target, ALLEGRO_BITMAP* texture, ALLEGRO_VERTEX_BUFFER* vertex_buffer, ALLEGRO_INDEX_BUFFER* index_buffer, int start, int end, int type)
877 {
878 #ifdef ALLEGRO_CFG_D3D
879    return draw_buffer_raw(target, texture, vertex_buffer, index_buffer, start, end, type);
880 #else
881    (void)target;
882    (void)texture;
883    (void)vertex_buffer;
884    (void)index_buffer;
885    (void)start;
886    (void)end;
887    (void)type;
888 
889    return 0;
890 #endif
891 }
892 
893 #ifdef ALLEGRO_CFG_D3D
convert_storage(int storage)894 static int convert_storage(int storage)
895 {
896    switch(storage) {
897       case ALLEGRO_PRIM_FLOAT_2:
898          return D3DDECLTYPE_FLOAT2;
899          break;
900       case ALLEGRO_PRIM_FLOAT_3:
901          return D3DDECLTYPE_FLOAT3;
902          break;
903       case ALLEGRO_PRIM_SHORT_2:
904          return D3DDECLTYPE_SHORT2;
905          break;
906       case ALLEGRO_PRIM_FLOAT_1:
907          return D3DDECLTYPE_FLOAT1;
908          break;
909       case ALLEGRO_PRIM_FLOAT_4:
910          return D3DDECLTYPE_FLOAT4;
911          break;
912       case ALLEGRO_PRIM_UBYTE_4:
913          return D3DDECLTYPE_UBYTE4;
914          break;
915       case ALLEGRO_PRIM_SHORT_4:
916          return D3DDECLTYPE_SHORT4;
917          break;
918       case ALLEGRO_PRIM_NORMALIZED_UBYTE_4:
919          return D3DDECLTYPE_UBYTE4N;
920          break;
921       case ALLEGRO_PRIM_NORMALIZED_SHORT_2:
922          return D3DDECLTYPE_SHORT2N;
923          break;
924       case ALLEGRO_PRIM_NORMALIZED_SHORT_4:
925          return D3DDECLTYPE_SHORT4N;
926          break;
927       case ALLEGRO_PRIM_NORMALIZED_USHORT_2:
928          return D3DDECLTYPE_USHORT2N;
929          break;
930       case ALLEGRO_PRIM_NORMALIZED_USHORT_4:
931          return D3DDECLTYPE_USHORT4N;
932          break;
933       case ALLEGRO_PRIM_HALF_FLOAT_2:
934          return D3DDECLTYPE_FLOAT16_2;
935          break;
936       case ALLEGRO_PRIM_HALF_FLOAT_4:
937          return D3DDECLTYPE_FLOAT16_4;
938          break;
939       default:
940          ASSERT(0);
941          return D3DDECLTYPE_UNUSED;
942    }
943 }
944 #endif
945 
_al_set_d3d_decl(ALLEGRO_DISPLAY * display,ALLEGRO_VERTEX_DECL * ret)946 void _al_set_d3d_decl(ALLEGRO_DISPLAY* display, ALLEGRO_VERTEX_DECL* ret)
947 {
948 #ifdef ALLEGRO_CFG_D3D
949    {
950       LPDIRECT3DDEVICE9 device;
951       D3DVERTEXELEMENT9 d3delements[ALLEGRO_PRIM_ATTR_NUM + 1];
952       int idx = 0;
953       ALLEGRO_VERTEX_ELEMENT* e;
954       D3DCAPS9 caps;
955 
956       device = al_get_d3d_device(display);
957 
958       device->GetDeviceCaps(&caps);
959       if(caps.PixelShaderVersion < D3DPS_VERSION(3, 0)) {
960          ret->d3d_decl = 0;
961       } else {
962          int i;
963          e = &ret->elements[ALLEGRO_PRIM_POSITION];
964          if(e->attribute) {
965             d3delements[idx].Stream = 0;
966             d3delements[idx].Offset = e->offset;
967             d3delements[idx].Type = convert_storage(e->storage);
968             d3delements[idx].Method = D3DDECLMETHOD_DEFAULT;
969             d3delements[idx].Usage = D3DDECLUSAGE_POSITION;
970             d3delements[idx].UsageIndex = 0;
971             idx++;
972          }
973 
974          e = &ret->elements[ALLEGRO_PRIM_TEX_COORD];
975          if(!e->attribute)
976             e = &ret->elements[ALLEGRO_PRIM_TEX_COORD_PIXEL];
977          if(e->attribute) {
978             d3delements[idx].Stream = 0;
979             d3delements[idx].Offset = e->offset;
980             d3delements[idx].Type = convert_storage(e->storage);
981             d3delements[idx].Method = D3DDECLMETHOD_DEFAULT;
982             d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD;
983             d3delements[idx].UsageIndex = 0;
984             idx++;
985          }
986 
987          e = &ret->elements[ALLEGRO_PRIM_COLOR_ATTR];
988          if(e->attribute) {
989             d3delements[idx].Stream = 0;
990             d3delements[idx].Offset = e->offset;
991             d3delements[idx].Type = D3DDECLTYPE_FLOAT4;
992             d3delements[idx].Method = D3DDECLMETHOD_DEFAULT;
993             d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD;
994             d3delements[idx].UsageIndex = 1;
995             idx++;
996          }
997 
998          for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) {
999             e = &ret->elements[ALLEGRO_PRIM_USER_ATTR + i];
1000             if (e->attribute) {
1001                d3delements[idx].Stream = 0;
1002                d3delements[idx].Offset = e->offset;
1003                d3delements[idx].Type = convert_storage(e->storage);
1004                d3delements[idx].Method = D3DDECLMETHOD_DEFAULT;
1005                d3delements[idx].Usage = D3DDECLUSAGE_TEXCOORD;
1006                d3delements[idx].UsageIndex = 2 + i;
1007                idx++;
1008             }
1009          }
1010 
1011          d3delements[idx].Stream = 0xFF;
1012          d3delements[idx].Offset = 0;
1013          d3delements[idx].Type = D3DDECLTYPE_UNUSED;
1014          d3delements[idx].Method = 0;
1015          d3delements[idx].Usage = 0;
1016          d3delements[idx].UsageIndex = 0;
1017 
1018          device->CreateVertexDeclaration(d3delements, (IDirect3DVertexDeclaration9**)&ret->d3d_decl);
1019       }
1020 
1021       _al_create_primitives_shader(device, ret);
1022    }
1023 #else
1024    (void)display;
1025    ret->d3d_decl = 0;
1026 #endif
1027 }
1028 
_al_create_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER * buf,const void * initial_data,size_t num_vertices,int flags)1029 bool _al_create_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf, const void* initial_data, size_t num_vertices, int flags)
1030 {
1031 #ifdef ALLEGRO_CFG_D3D
1032    LPDIRECT3DDEVICE9 device;
1033    IDirect3DVertexBuffer9* d3d_vbuff;
1034    DWORD fvf = A5V_FVF;
1035    int stride = buf->decl ? buf->decl->stride : (int)sizeof(ALLEGRO_VERTEX);
1036    HRESULT res;
1037    void* locked_memory;
1038 
1039    /* There's just no point */
1040    if (is_legacy_card()) {
1041       ALLEGRO_WARN("Cannot create vertex buffer for a legacy card.\n");
1042       return false;
1043    }
1044 
1045    device = al_get_d3d_device(al_get_current_display());
1046 
1047    if (buf->decl) {
1048       device->SetVertexDeclaration((IDirect3DVertexDeclaration9*)buf->decl->d3d_decl);
1049       fvf = 0;
1050    }
1051 
1052    res = device->CreateVertexBuffer(stride * num_vertices, !(flags & ALLEGRO_PRIM_BUFFER_READWRITE) ? D3DUSAGE_WRITEONLY : 0,
1053                                     fvf, D3DPOOL_MANAGED, &d3d_vbuff, 0);
1054    if (res != D3D_OK) {
1055       ALLEGRO_WARN("CreateVertexBuffer failed: %ld.\n", res);
1056       return false;
1057    }
1058 
1059    if (initial_data != NULL) {
1060       d3d_vbuff->Lock(0, 0, &locked_memory, 0);
1061       memcpy(locked_memory, initial_data, stride * num_vertices);
1062       d3d_vbuff->Unlock();
1063    }
1064 
1065    buf->common.handle = (uintptr_t)d3d_vbuff;
1066 
1067    return true;
1068 #else
1069    (void)buf;
1070    (void)initial_data;
1071    (void)num_vertices;
1072    (void)flags;
1073 
1074    return false;
1075 #endif
1076 }
1077 
_al_create_index_buffer_directx(ALLEGRO_INDEX_BUFFER * buf,const void * initial_data,size_t num_indices,int flags)1078 bool _al_create_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf, const void* initial_data, size_t num_indices, int flags)
1079 {
1080 #ifdef ALLEGRO_CFG_D3D
1081    LPDIRECT3DDEVICE9 device;
1082    IDirect3DIndexBuffer9* d3d_ibuff;
1083    HRESULT res;
1084    void* locked_memory;
1085 
1086    /* There's just no point */
1087    if (is_legacy_card()) {
1088       ALLEGRO_WARN("Cannot create index buffer for a legacy card.\n");
1089       return false;
1090    }
1091 
1092    device = al_get_d3d_device(al_get_current_display());
1093 
1094    res = device->CreateIndexBuffer(num_indices * buf->index_size, !(flags & ALLEGRO_PRIM_BUFFER_READWRITE) ? D3DUSAGE_WRITEONLY : 0,
1095                                    buf->index_size == 4 ? D3DFMT_INDEX32 : D3DFMT_INDEX16, D3DPOOL_MANAGED, &d3d_ibuff, 0);
1096    if (res != D3D_OK) {
1097       ALLEGRO_WARN("CreateIndexBuffer failed: %ld.\n", res);
1098       return false;
1099    }
1100 
1101    if (initial_data != NULL) {
1102       d3d_ibuff->Lock(0, 0, &locked_memory, 0);
1103       memcpy(locked_memory, initial_data, num_indices * buf->index_size);
1104       d3d_ibuff->Unlock();
1105    }
1106 
1107    buf->common.handle = (uintptr_t)d3d_ibuff;
1108 
1109    return true;
1110 #else
1111    (void)buf;
1112    (void)initial_data;
1113    (void)num_indices;
1114    (void)flags;
1115 
1116    return false;
1117 #endif
1118 }
1119 
_al_destroy_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER * buf)1120 void _al_destroy_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf)
1121 {
1122 #ifdef ALLEGRO_CFG_D3D
1123    ((IDirect3DVertexBuffer9*)buf->common.handle)->Release();
1124 #else
1125    (void)buf;
1126 #endif
1127 }
1128 
_al_destroy_index_buffer_directx(ALLEGRO_INDEX_BUFFER * buf)1129 void _al_destroy_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf)
1130 {
1131 #ifdef ALLEGRO_CFG_D3D
1132    ((IDirect3DIndexBuffer9*)buf->common.handle)->Release();
1133 #else
1134    (void)buf;
1135 #endif
1136 }
1137 
_al_lock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER * buf)1138 void* _al_lock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf)
1139 {
1140 #ifdef ALLEGRO_CFG_D3D
1141    DWORD flags = buf->common.lock_flags == ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0;
1142    HRESULT res;
1143 
1144    res = ((IDirect3DVertexBuffer9*)buf->common.handle)->Lock((UINT)buf->common.lock_offset, (UINT)buf->common.lock_length, &buf->common.locked_memory, flags);
1145    if (res != D3D_OK) {
1146       ALLEGRO_WARN("Locking vertex buffer failed: %ld.\n", res);
1147       return 0;
1148    }
1149 
1150    return buf->common.locked_memory;
1151 #else
1152    (void)buf;
1153 
1154    return 0;
1155 #endif
1156 }
1157 
_al_lock_index_buffer_directx(ALLEGRO_INDEX_BUFFER * buf)1158 void* _al_lock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf)
1159 {
1160 #ifdef ALLEGRO_CFG_D3D
1161    DWORD flags = buf->common.lock_flags == ALLEGRO_LOCK_READONLY ? D3DLOCK_READONLY : 0;
1162    HRESULT res;
1163 
1164    res = ((IDirect3DIndexBuffer9*)buf->common.handle)->Lock((UINT)buf->common.lock_offset, (UINT)buf->common.lock_length, &buf->common.locked_memory, flags);
1165 
1166    if (res != D3D_OK) {
1167       ALLEGRO_WARN("Locking index buffer failed: %ld.\n", res);
1168       return 0;
1169    }
1170 
1171    return buf->common.locked_memory;
1172 #else
1173    (void)buf;
1174 
1175    return 0;
1176 #endif
1177 }
1178 
_al_unlock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER * buf)1179 void _al_unlock_vertex_buffer_directx(ALLEGRO_VERTEX_BUFFER* buf)
1180 {
1181 #ifdef ALLEGRO_CFG_D3D
1182    ((IDirect3DVertexBuffer9*)buf->common.handle)->Unlock();
1183 #else
1184    (void)buf;
1185 #endif
1186 }
1187 
_al_unlock_index_buffer_directx(ALLEGRO_INDEX_BUFFER * buf)1188 void _al_unlock_index_buffer_directx(ALLEGRO_INDEX_BUFFER* buf)
1189 {
1190 #ifdef ALLEGRO_CFG_D3D
1191    ((IDirect3DIndexBuffer9*)buf->common.handle)->Unlock();
1192 #else
1193    (void)buf;
1194 #endif
1195 }
1196