1 /*  RetroArch - A frontend for libretro.
2  *  Copyright (C) 2014-2018 - Ali Bouhlel
3  *
4  *  RetroArch is free software: you can redistribute it and/or modify it under the terms
5  *  of the GNU General Public License as published by the Free Software Found-
6  *  ation, either version 3 of the License, or (at your option) any later version.
7  *
8  *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9  *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10  *  PURPOSE.  See the GNU General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License along with RetroArch.
13  *  If not, see <http://www.gnu.org/licenses/>.
14  */
15 
16 #define CINTERFACE
17 
18 #include <retro_miscellaneous.h>
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #include "../gfx_display.h"
25 
26 #include "../../retroarch.h"
27 #include "../font_driver.h"
28 #include "../common/d3d11_common.h"
29 
gfx_display_d3d11_blend_begin(void * data)30 static void gfx_display_d3d11_blend_begin(void *data)
31 {
32    d3d11_video_t* d3d11 = (d3d11_video_t*)data;
33    D3D11SetBlendState(d3d11->context,
34          d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK);
35 }
36 
gfx_display_d3d11_blend_end(void * data)37 static void gfx_display_d3d11_blend_end(void *data)
38 {
39    d3d11_video_t* d3d11 = (d3d11_video_t*)data;
40    D3D11SetBlendState(d3d11->context,
41          d3d11->blend_disable, NULL, D3D11_DEFAULT_SAMPLE_MASK);
42 }
43 
gfx_display_d3d11_draw(gfx_display_ctx_draw_t * draw,void * data,unsigned video_width,unsigned video_height)44 static void gfx_display_d3d11_draw(gfx_display_ctx_draw_t *draw,
45       void *data, unsigned video_width, unsigned video_height)
46 {
47    int vertex_count     = 1;
48    d3d11_video_t *d3d11 = (d3d11_video_t*)data;
49 
50    if (!d3d11 || !draw || !draw->texture)
51       return;
52 
53    switch (draw->pipeline_id)
54    {
55       case VIDEO_SHADER_MENU:
56       case VIDEO_SHADER_MENU_2:
57       case VIDEO_SHADER_MENU_3:
58       case VIDEO_SHADER_MENU_4:
59       case VIDEO_SHADER_MENU_5:
60       case VIDEO_SHADER_MENU_6:
61          d3d11_set_shader(d3d11->context, &d3d11->shaders[draw->pipeline_id]);
62          D3D11Draw(d3d11->context, draw->coords->vertices, 0);
63 
64          D3D11SetBlendState(d3d11->context, d3d11->blend_enable, NULL, D3D11_DEFAULT_SAMPLE_MASK);
65          d3d11_set_shader(d3d11->context, &d3d11->sprites.shader);
66          D3D11SetVertexBuffer(d3d11->context, 0, d3d11->sprites.vbo, sizeof(d3d11_sprite_t), 0);
67          D3D11SetPrimitiveTopology(d3d11->context, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
68          return;
69    }
70 
71    if (draw->coords->vertex && draw->coords->tex_coord && draw->coords->color)
72       vertex_count = draw->coords->vertices;
73 
74    if (!d3d11->sprites.enabled || vertex_count > d3d11->sprites.capacity)
75       return;
76 
77    if (d3d11->sprites.offset + vertex_count > d3d11->sprites.capacity)
78       d3d11->sprites.offset = 0;
79 
80    {
81       D3D11_MAPPED_SUBRESOURCE mapped_vbo;
82       d3d11_sprite_t*          sprite = NULL;
83 
84       D3D11MapBuffer(
85             d3d11->context, d3d11->sprites.vbo, 0, D3D11_MAP_WRITE_NO_OVERWRITE, 0, &mapped_vbo);
86 
87       sprite = (d3d11_sprite_t*)mapped_vbo.pData + d3d11->sprites.offset;
88 
89       if (vertex_count == 1)
90       {
91          sprite->pos.x = draw->x / (float)d3d11->viewport.Width;
92          sprite->pos.y =
93                (d3d11->viewport.Height - draw->y - draw->height) / (float)d3d11->viewport.Height;
94          sprite->pos.w = draw->width / (float)d3d11->viewport.Width;
95          sprite->pos.h = draw->height / (float)d3d11->viewport.Height;
96 
97          sprite->coords.u = 0.0f;
98          sprite->coords.v = 0.0f;
99          sprite->coords.w = 1.0f;
100          sprite->coords.h = 1.0f;
101 
102          if (draw->scale_factor)
103             sprite->params.scaling = draw->scale_factor;
104          else
105             sprite->params.scaling = 1.0f;
106 
107          sprite->params.rotation = draw->rotation;
108 
109          sprite->colors[3] = DXGI_COLOR_RGBA(
110                0xFF * draw->coords->color[0], 0xFF * draw->coords->color[1],
111                0xFF * draw->coords->color[2], 0xFF * draw->coords->color[3]);
112          sprite->colors[2] = DXGI_COLOR_RGBA(
113                0xFF * draw->coords->color[4], 0xFF * draw->coords->color[5],
114                0xFF * draw->coords->color[6], 0xFF * draw->coords->color[7]);
115          sprite->colors[1] = DXGI_COLOR_RGBA(
116                0xFF * draw->coords->color[8], 0xFF * draw->coords->color[9],
117                0xFF * draw->coords->color[10], 0xFF * draw->coords->color[11]);
118          sprite->colors[0] = DXGI_COLOR_RGBA(
119                0xFF * draw->coords->color[12], 0xFF * draw->coords->color[13],
120                0xFF * draw->coords->color[14], 0xFF * draw->coords->color[15]);
121       }
122       else
123       {
124          int          i;
125          const float* vertex    = draw->coords->vertex;
126          const float* tex_coord = draw->coords->tex_coord;
127          const float* color     = draw->coords->color;
128 
129          for (i = 0; i < vertex_count; i++)
130          {
131             d3d11_vertex_t* v = (d3d11_vertex_t*)sprite;
132             v->position[0]    = *vertex++;
133             v->position[1]    = *vertex++;
134             v->texcoord[0]    = *tex_coord++;
135             v->texcoord[1]    = *tex_coord++;
136             v->color[0]       = *color++;
137             v->color[1]       = *color++;
138             v->color[2]       = *color++;
139             v->color[3]       = *color++;
140 
141             sprite++;
142          }
143 
144          d3d11_set_shader(d3d11->context, &d3d11->shaders[VIDEO_SHADER_STOCK_BLEND]);
145          D3D11SetPrimitiveTopology(d3d11->context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
146       }
147 
148       D3D11UnmapBuffer(d3d11->context, d3d11->sprites.vbo, 0);
149    }
150 
151    d3d11_set_texture_and_sampler(d3d11->context, 0, (d3d11_texture_t*)draw->texture);
152    D3D11Draw(d3d11->context, vertex_count, d3d11->sprites.offset);
153    d3d11->sprites.offset += vertex_count;
154 
155    if (vertex_count > 1)
156    {
157       d3d11_set_shader(d3d11->context, &d3d11->sprites.shader);
158       D3D11SetPrimitiveTopology(d3d11->context, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST);
159    }
160 
161    return;
162 }
163 
gfx_display_d3d11_draw_pipeline(gfx_display_ctx_draw_t * draw,gfx_display_t * p_disp,void * data,unsigned video_width,unsigned video_height)164 static void gfx_display_d3d11_draw_pipeline(gfx_display_ctx_draw_t *draw,
165       gfx_display_t *p_disp,
166       void *data, unsigned video_width, unsigned video_height)
167 {
168    d3d11_video_t *d3d11 = (d3d11_video_t*)data;
169 
170    if (!d3d11 || !draw)
171       return;
172 
173    switch (draw->pipeline_id)
174    {
175       case VIDEO_SHADER_MENU:
176       case VIDEO_SHADER_MENU_2:
177       {
178          video_coord_array_t* ca   = &p_disp->dispca;
179 
180          if (!d3d11->menu_pipeline_vbo)
181          {
182             D3D11_BUFFER_DESC desc = { 0 };
183             desc.Usage             = D3D11_USAGE_IMMUTABLE;
184             desc.ByteWidth         = ca->coords.vertices * 2 * sizeof(float);
185             desc.BindFlags         = D3D11_BIND_VERTEX_BUFFER;
186 
187 			{
188                D3D11_SUBRESOURCE_DATA vertexData = { ca->coords.vertex };
189                D3D11CreateBuffer(d3d11->device, &desc, &vertexData, &d3d11->menu_pipeline_vbo);
190 			}
191          }
192          D3D11SetVertexBuffer(d3d11->context, 0, d3d11->menu_pipeline_vbo, 2 * sizeof(float), 0);
193          draw->coords->vertices = ca->coords.vertices;
194          D3D11SetBlendState(d3d11->context, d3d11->blend_pipeline, NULL, D3D11_DEFAULT_SAMPLE_MASK);
195          break;
196       }
197 
198       case VIDEO_SHADER_MENU_3:
199       case VIDEO_SHADER_MENU_4:
200       case VIDEO_SHADER_MENU_5:
201       case VIDEO_SHADER_MENU_6:
202          D3D11SetVertexBuffer(d3d11->context, 0, d3d11->frame.vbo, sizeof(d3d11_vertex_t), 0);
203          draw->coords->vertices = 4;
204          break;
205       default:
206          return;
207    }
208 
209    D3D11SetPrimitiveTopology(d3d11->context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
210 
211    d3d11->ubo_values.time += 0.01f;
212 
213    {
214       D3D11_MAPPED_SUBRESOURCE mapped_ubo;
215       D3D11MapBuffer(d3d11->context, d3d11->ubo, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_ubo);
216       *(d3d11_uniform_t*)mapped_ubo.pData = d3d11->ubo_values;
217       D3D11UnmapBuffer(d3d11->context, d3d11->ubo, 0);
218    }
219 }
220 
gfx_display_d3d11_font_init_first(void ** font_handle,void * video_data,const char * font_path,float menu_font_size,bool is_threaded)221 static bool gfx_display_d3d11_font_init_first(
222       void**      font_handle,
223       void*       video_data,
224       const char* font_path,
225       float       menu_font_size,
226       bool        is_threaded)
227 {
228    font_data_t** handle     = (font_data_t**)font_handle;
229    font_data_t*  new_handle = font_driver_init_first(
230          video_data, font_path, menu_font_size, true,
231          is_threaded, FONT_DRIVER_RENDER_D3D11_API);
232    if (!new_handle)
233       return false;
234    *handle = new_handle;
235    return true;
236 }
237 
gfx_display_d3d11_scissor_begin(void * data,unsigned video_width,unsigned video_height,int x,int y,unsigned width,unsigned height)238 void gfx_display_d3d11_scissor_begin(void *data,
239       unsigned video_width,
240       unsigned video_height,
241       int x, int y, unsigned width, unsigned height)
242 {
243    D3D11_RECT rect;
244    d3d11_video_t *d3d11 = (d3d11_video_t*)data;
245 
246    if (!d3d11 || !width || !height)
247       return;
248 
249    rect.left            = x;
250    rect.top             = y;
251    rect.right           = width + x;
252    rect.bottom          = height + y;
253 
254    D3D11SetScissorRects(d3d11->context, 1, &rect);
255 }
256 
gfx_display_d3d11_scissor_end(void * data,unsigned video_width,unsigned video_height)257 void gfx_display_d3d11_scissor_end(void *data,
258       unsigned video_width,
259       unsigned video_height)
260 {
261    D3D11_RECT rect;
262    d3d11_video_t *d3d11  = (d3d11_video_t*)data;
263 
264    if (!d3d11)
265       return;
266 
267    rect.left            = 0;
268    rect.top             = 0;
269    rect.right           = video_width;
270    rect.bottom          = video_height;
271 
272    D3D11SetScissorRects(d3d11->context, 1, &rect);
273 }
274 
275 gfx_display_ctx_driver_t gfx_display_ctx_d3d11 = {
276    gfx_display_d3d11_draw,
277    gfx_display_d3d11_draw_pipeline,
278    gfx_display_d3d11_blend_begin,
279    gfx_display_d3d11_blend_end,
280    NULL,                                     /* get_default_mvp */
281    NULL,                                     /* get_default_vertices */
282    NULL,                                     /* get_default_tex_coords */
283    gfx_display_d3d11_font_init_first,
284    GFX_VIDEO_DRIVER_DIRECT3D11,
285    "d3d11",
286    true,
287    gfx_display_d3d11_scissor_begin,
288    gfx_display_d3d11_scissor_end
289 };
290