drawprim.c 28 KB
Newer Older
1 2 3 4 5
/*
 * WINED3D draw functions
 *
 * Copyright 2002-2004 Jason Edmeades
 * Copyright 2002-2004 Raphael Junqueira
6
 * Copyright 2004 Christian Costa
7
 * Copyright 2005 Oliver Stieber
8
 * Copyright 2006, 2008 Henri Verbeet
9
 * Copyright 2007-2008 Stefan Dösinger for CodeWeavers
10
 * Copyright 2009 Henri Verbeet for CodeWeavers
11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
25 26 27
 */

#include "config.h"
Henri Verbeet's avatar
Henri Verbeet committed
28 29
#include "wine/port.h"

30 31
#include "wined3d_private.h"

32
WINE_DEFAULT_DEBUG_CHANNEL(d3d_draw);
33
WINE_DECLARE_DEBUG_CHANNEL(d3d_perf);
34
WINE_DECLARE_DEBUG_CHANNEL(d3d);
35

36
/* Context activation is done by the caller. */
37
static void draw_primitive_arrays(struct wined3d_context *context, const struct wined3d_state *state,
38 39
        const void *idx_data, unsigned int idx_size, int base_vertex_idx, unsigned int start_idx,
        unsigned int count, unsigned int start_instance, unsigned int instance_count)
40
{
41 42 43 44 45 46 47 48 49
    const struct wined3d_ffp_attrib_ops *ops = &context->d3d_info->ffp_attrib_ops;
    GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
    const struct wined3d_stream_info *si = &context->stream_info;
    unsigned int instanced_elements[ARRAY_SIZE(si->elements)];
    const struct wined3d_gl_info *gl_info = context->gl_info;
    unsigned int instanced_element_count = 0;
    unsigned int i, j;

    if (!instance_count)
50
    {
51
        if (!idx_size)
52
        {
53 54 55
            gl_info->gl_ops.gl.p_glDrawArrays(state->gl_primitive_type, start_idx, count);
            checkGLcall("glDrawArrays");
            return;
56
        }
57 58

        if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
59
        {
60
            GL_EXTCALL(glDrawElementsBaseVertex(state->gl_primitive_type, count, idx_type,
61
                    (const char *)idx_data + (idx_size * start_idx), base_vertex_idx));
62
            checkGLcall("glDrawElementsBaseVertex");
63
            return;
64
        }
65 66 67 68 69 70 71

        gl_info->gl_ops.gl.p_glDrawElements(state->gl_primitive_type, count,
                idx_type, (const char *)idx_data + (idx_size * start_idx));
        checkGLcall("glDrawElements");
        return;
    }

72
    if (start_instance && !(gl_info->supported[ARB_BASE_INSTANCE] && gl_info->supported[ARB_INSTANCED_ARRAYS]))
73 74 75 76 77
        FIXME("Start instance (%u) not supported.\n", start_instance);

    if (gl_info->supported[ARB_INSTANCED_ARRAYS])
    {
        if (!idx_size)
78
        {
79 80 81 82 83 84 85
            if (gl_info->supported[ARB_BASE_INSTANCE])
            {
                GL_EXTCALL(glDrawArraysInstancedBaseInstance(state->gl_primitive_type, start_idx, count, instance_count, start_instance));
                checkGLcall("glDrawArraysInstancedBaseInstance");
                return;
            }

86 87 88 89 90
            GL_EXTCALL(glDrawArraysInstanced(state->gl_primitive_type, start_idx, count, instance_count));
            checkGLcall("glDrawArraysInstanced");
            return;
        }

91 92 93 94 95 96 97
        if (gl_info->supported[ARB_BASE_INSTANCE])
        {
            GL_EXTCALL(glDrawElementsInstancedBaseVertexBaseInstance(state->gl_primitive_type, count, idx_type,
                        (const char *)idx_data + (idx_size * start_idx), instance_count, base_vertex_idx, start_instance));
            checkGLcall("glDrawElementsInstancedBaseVertexBaseInstance");
            return;
        }
98 99 100
        if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
        {
            GL_EXTCALL(glDrawElementsInstancedBaseVertex(state->gl_primitive_type, count, idx_type,
101
                        (const char *)idx_data + (idx_size * start_idx), instance_count, base_vertex_idx));
102 103
            checkGLcall("glDrawElementsInstancedBaseVertex");
            return;
104
        }
105 106 107 108 109

        GL_EXTCALL(glDrawElementsInstanced(state->gl_primitive_type, count, idx_type,
                    (const char *)idx_data + (idx_size * start_idx), instance_count));
        checkGLcall("glDrawElementsInstanced");
        return;
110
    }
111 112 113 114 115 116 117 118 119 120 121

    /* Instancing emulation by mixing immediate mode and arrays. */

    /* This is a nasty thing. MSDN says no hardware supports this and
     * applications have to use software vertex processing. We don't support
     * this for now.
     *
     * Shouldn't be too hard to support with OpenGL, in theory just call
     * glDrawArrays() instead of drawElements(). But the stream fequency value
     * has a different meaning in that situation. */
    if (!idx_size)
122
    {
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
        FIXME("Non-indexed instanced drawing is not supported\n");
        return;
    }

    for (i = 0; i < ARRAY_SIZE(si->elements); ++i)
    {
        if (!(si->use_map & (1u << i)))
            continue;

        if (state->streams[si->elements[i].stream_idx].flags & WINED3DSTREAMSOURCE_INSTANCEDATA)
            instanced_elements[instanced_element_count++] = i;
    }

    for (i = 0; i < instance_count; ++i)
    {
        /* Specify the instanced attributes using immediate mode calls. */
        for (j = 0; j < instanced_element_count; ++j)
140
        {
141 142 143 144 145 146 147 148
            const struct wined3d_stream_info_element *element;
            unsigned int element_idx;
            const BYTE *ptr;

            element_idx = instanced_elements[j];
            element = &si->elements[element_idx];
            ptr = element->data.addr + element->stride * i;
            if (element->data.buffer_object)
149
                ptr += (ULONG_PTR)wined3d_buffer_load_sysmem(state->streams[element->stream_idx].buffer, context);
150 151 152 153 154 155
            ops->generic[element->format->emit_idx](element_idx, ptr);
        }

        if (gl_info->supported[ARB_DRAW_ELEMENTS_BASE_VERTEX])
        {
            GL_EXTCALL(glDrawElementsBaseVertex(state->gl_primitive_type, count, idx_type,
156
                        (const char *)idx_data + (idx_size * start_idx), base_vertex_idx));
157
            checkGLcall("glDrawElementsBaseVertex");
158 159 160
        }
        else
        {
161 162 163
            gl_info->gl_ops.gl.p_glDrawElements(state->gl_primitive_type, count, idx_type,
                        (const char *)idx_data + (idx_size * start_idx));
            checkGLcall("glDrawElements");
164
        }
165 166 167
    }
}

168 169 170 171 172 173 174 175 176
static unsigned int get_stride_idx(const void *idx_data, unsigned int idx_size,
        unsigned int base_vertex_idx, unsigned int start_idx, unsigned int vertex_idx)
{
    if (!idx_data)
        return start_idx + vertex_idx;
    if (idx_size == 2)
        return ((const WORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
    return ((const DWORD *)idx_data)[start_idx + vertex_idx] + base_vertex_idx;
}
177

178
/* Context activation is done by the caller. */
179
static void draw_primitive_immediate_mode(struct wined3d_context *context, const struct wined3d_state *state,
180 181
        const struct wined3d_stream_info *si, const void *idx_data, unsigned int idx_size,
        int base_vertex_idx, unsigned int start_idx, unsigned int vertex_count, unsigned int instance_count)
182
{
183
    const BYTE *position = NULL, *normal = NULL, *diffuse = NULL, *specular = NULL;
184
    const struct wined3d_d3d_info *d3d_info = context->d3d_info;
185 186
    unsigned int coord_idx, stride_idx, texture_idx, vertex_idx;
    const struct wined3d_gl_info *gl_info = context->gl_info;
187
    const struct wined3d_stream_info_element *element;
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
    const BYTE *tex_coords[WINED3DDP_MAXTEXCOORD];
    unsigned int texture_unit, texture_stages;
    const struct wined3d_ffp_attrib_ops *ops;
    unsigned int untracked_material_count;
    unsigned int tex_mask = 0;
    BOOL specular_fog = FALSE;
    BOOL ps = use_ps(state);
    const void *ptr;

    static unsigned int once;

    if (!once++)
        FIXME_(d3d_perf)("Drawing using immediate mode.\n");
    else
        WARN_(d3d_perf)("Drawing using immediate mode.\n");
203

204 205
    if (!idx_size && idx_data)
        ERR("Non-NULL idx_data with 0 idx_size, this should never happen.\n");
206

207 208 209
    if (instance_count)
        FIXME("Instancing not implemented.\n");

210 211 212 213
    /* Immediate mode drawing can't make use of indices in a VBO - get the
     * data from the index buffer. */
    if (idx_size)
        idx_data = wined3d_buffer_load_sysmem(state->index_buffer, context) + state->index_offset;
214 215 216 217 218 219

    ops = &d3d_info->ffp_attrib_ops;

    gl_info->gl_ops.gl.p_glBegin(state->gl_primitive_type);

    if (use_vs(state) || d3d_info->ffp_generic_attributes)
220
    {
221 222 223 224 225
        for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
        {
            unsigned int use_map = si->use_map;
            unsigned int element_idx;

226
            stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
227
            for (element_idx = MAX_ATTRIBS - 1; use_map; use_map &= ~(1u << element_idx), --element_idx)
228
            {
229
                if (!(use_map & 1u << element_idx))
230 231 232 233 234 235 236 237
                    continue;

                ptr = si->elements[element_idx].data.addr + si->elements[element_idx].stride * stride_idx;
                ops->generic[si->elements[element_idx].format->emit_idx](element_idx, ptr);
            }
        }

        gl_info->gl_ops.gl.p_glEnd();
238
        return;
239 240
    }

241
    if (si->use_map & (1u << WINED3D_FFP_POSITION))
242
        position = si->elements[WINED3D_FFP_POSITION].data.addr;
243

244
    if (si->use_map & (1u << WINED3D_FFP_NORMAL))
245
        normal = si->elements[WINED3D_FFP_NORMAL].data.addr;
246
    else
247
        gl_info->gl_ops.gl.p_glNormal3f(0.0f, 0.0f, 0.0f);
248

249
    untracked_material_count = context->num_untracked_materials;
250
    if (si->use_map & (1u << WINED3D_FFP_DIFFUSE))
251 252
    {
        element = &si->elements[WINED3D_FFP_DIFFUSE];
253
        diffuse = element->data.addr;
254

255 256
        if (untracked_material_count && element->format->id != WINED3DFMT_B8G8R8A8_UNORM)
            FIXME("Implement diffuse color tracking from %s.\n", debug_d3dformat(element->format->id));
257 258 259
    }
    else
    {
260
        gl_info->gl_ops.gl.p_glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
261
    }
262

263
    if (si->use_map & (1u << WINED3D_FFP_SPECULAR))
264
    {
265
        element = &si->elements[WINED3D_FFP_SPECULAR];
266
        specular = element->data.addr;
267

268
        /* Special case where the fog density is stored in the specular alpha channel. */
269
        if (state->render_states[WINED3D_RS_FOGENABLE]
270
                && (state->render_states[WINED3D_RS_FOGVERTEXMODE] == WINED3D_FOG_NONE
271
                    || si->elements[WINED3D_FFP_POSITION].format->id == WINED3DFMT_R32G32B32A32_FLOAT)
272
                && state->render_states[WINED3D_RS_FOGTABLEMODE] == WINED3D_FOG_NONE)
273
        {
274
            if (gl_info->supported[EXT_FOG_COORD])
275
            {
276 277 278 279
                if (element->format->id == WINED3DFMT_B8G8R8A8_UNORM)
                    specular_fog = TRUE;
                else
                    FIXME("Implement fog coordinates from %s.\n", debug_d3dformat(element->format->id));
280 281 282
            }
            else
            {
283
                static unsigned int once;
284

285 286
                if (!once++)
                    FIXME("Implement fog for transformed vertices in software.\n");
287 288
            }
        }
289
    }
290
    else if (gl_info->supported[EXT_SECONDARY_COLOR])
291
    {
292
        GL_EXTCALL(glSecondaryColor3fEXT)(0.0f, 0.0f, 0.0f);
293 294
    }

295 296
    texture_stages = d3d_info->limits.ffp_blend_stages;
    for (texture_idx = 0; texture_idx < texture_stages; ++texture_idx)
297
    {
298
        if (!gl_info->supported[ARB_MULTITEXTURE] && texture_idx > 0)
299
        {
300
            FIXME("Program using multiple concurrent textures which this OpenGL implementation doesn't support.\n");
301 302 303
            continue;
        }

304 305
        if (!ps && !state->textures[texture_idx])
            continue;
306

307 308
        texture_unit = context->tex_unit_map[texture_idx];
        if (texture_unit == WINED3D_UNMAPPED_STAGE)
309
            continue;
310 311 312

        coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
        if (coord_idx > 7)
313
        {
314
            TRACE("Skipping generated coordinates (%#x) for texture %u.\n", coord_idx, texture_idx);
315 316 317
            continue;
        }

318
        if (si->use_map & (1u << (WINED3D_FFP_TEXCOORD0 + coord_idx)))
319
        {
320 321
            tex_coords[coord_idx] = si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].data.addr;
            tex_mask |= (1u << texture_idx);
322 323 324
        }
        else
        {
325
            TRACE("Setting default coordinates for texture %u.\n", texture_idx);
326
            if (gl_info->supported[ARB_MULTITEXTURE])
327
                GL_EXTCALL(glMultiTexCoord4fARB(GL_TEXTURE0_ARB + texture_unit, 0.0f, 0.0f, 0.0f, 1.0f));
328
            else
329
                gl_info->gl_ops.gl.p_glTexCoord4f(0.0f, 0.0f, 0.0f, 1.0f);
330 331 332
        }
    }

333 334 335 336 337 338
    /* Blending data and point sizes are not supported by this function. They
     * are not supported by the fixed function pipeline at all. A FIXME for
     * them is printed after decoding the vertex declaration. */
    for (vertex_idx = 0; vertex_idx < vertex_count; ++vertex_idx)
    {
        unsigned int tmp_tex_mask;
339

340
        stride_idx = get_stride_idx(idx_data, idx_size, base_vertex_idx, start_idx, vertex_idx);
341

342
        if (normal)
343
        {
344 345
            ptr = normal + stride_idx * si->elements[WINED3D_FFP_NORMAL].stride;
            ops->normal[si->elements[WINED3D_FFP_NORMAL].format->emit_idx](ptr);
346
        }
347

348 349
        if (diffuse)
        {
350 351
            ptr = diffuse + stride_idx * si->elements[WINED3D_FFP_DIFFUSE].stride;
            ops->diffuse[si->elements[WINED3D_FFP_DIFFUSE].format->emit_idx](ptr);
352

353
            if (untracked_material_count)
354
            {
355
                struct wined3d_color color;
356
                unsigned int i;
357

358 359
                wined3d_color_from_d3dcolor(&color, *(const DWORD *)ptr);
                for (i = 0; i < untracked_material_count; ++i)
360
                {
361
                    gl_info->gl_ops.gl.p_glMaterialfv(GL_FRONT_AND_BACK, context->untracked_materials[i], &color.r);
362 363
                }
            }
364 365
        }

366 367
        if (specular)
        {
368 369
            ptr = specular + stride_idx * si->elements[WINED3D_FFP_SPECULAR].stride;
            ops->specular[si->elements[WINED3D_FFP_SPECULAR].format->emit_idx](ptr);
370 371

            if (specular_fog)
372
                GL_EXTCALL(glFogCoordfEXT((float)(*(const DWORD *)ptr >> 24)));
373 374
        }

375 376
        tmp_tex_mask = tex_mask;
        for (texture_idx = 0; tmp_tex_mask; tmp_tex_mask >>= 1, ++texture_idx)
377
        {
378 379
            if (!(tmp_tex_mask & 1))
                continue;
380

381 382 383 384
            coord_idx = state->texture_states[texture_idx][WINED3D_TSS_TEXCOORD_INDEX];
            ptr = tex_coords[coord_idx] + (stride_idx * si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].stride);
            ops->texcoord[si->elements[WINED3D_FFP_TEXCOORD0 + coord_idx].format->emit_idx](
                    GL_TEXTURE0_ARB + context->tex_unit_map[texture_idx], ptr);
385
        }
386 387 388 389 390 391

        if (position)
        {
            ptr = position + stride_idx * si->elements[WINED3D_FFP_POSITION].stride;
            ops->position[si->elements[WINED3D_FFP_POSITION].format->emit_idx](ptr);
        }
392 393
    }

394
    gl_info->gl_ops.gl.p_glEnd();
395 396 397
    checkGLcall("glEnd and previous calls");
}

398 399 400 401 402 403
static void draw_indirect(struct wined3d_context *context, const struct wined3d_state *state,
        const struct wined3d_indirect_draw_parameters *parameters, unsigned int idx_size)
{
    const struct wined3d_gl_info *gl_info = context->gl_info;
    struct wined3d_buffer *buffer = parameters->buffer;

404 405 406 407 408 409
    if (!gl_info->supported[ARB_DRAW_INDIRECT])
    {
        FIXME("OpenGL implementation does not support indirect draws.\n");
        return;
    }

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
    wined3d_buffer_load(buffer, context, state);
    GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, buffer->buffer_object));

    if (idx_size)
    {
        GLenum idx_type = idx_size == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
        if (state->index_offset)
            FIXME("Ignoring index offset %u.\n", state->index_offset);
        GL_EXTCALL(glDrawElementsIndirect(state->gl_primitive_type, idx_type,
                (void *)(GLintptr)parameters->offset));
    }
    else
    {
        GL_EXTCALL(glDrawArraysIndirect(state->gl_primitive_type,
                (void *)(GLintptr)parameters->offset));
    }

    GL_EXTCALL(glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0));

    checkGLcall("draw indirect");
}

432
static void remove_vbos(struct wined3d_context *context,
433
        const struct wined3d_state *state, struct wined3d_stream_info *s)
434
{
435
    unsigned int i;
436

437
    for (i = 0; i < ARRAY_SIZE(s->elements); ++i)
438
    {
439 440
        struct wined3d_stream_info_element *e;

441 442
        if (!(s->use_map & (1u << i)))
            continue;
443 444

        e = &s->elements[i];
445
        if (e->data.buffer_object)
446
        {
447
            struct wined3d_buffer *vb = state->streams[e->stream_idx].buffer;
448
            e->data.buffer_object = 0;
449
            e->data.addr += (ULONG_PTR)wined3d_buffer_load_sysmem(vb, context);
450 451 452 453
        }
    }
}

454 455 456 457 458 459 460 461
static BOOL use_transform_feedback(const struct wined3d_state *state)
{
    const struct wined3d_shader *shader;
    if (!(shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY]))
        return FALSE;
    return shader->u.gs.so_desc.element_count;
}

462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
static void context_pause_transform_feedback(struct wined3d_context *context, BOOL force)
{
    const struct wined3d_gl_info *gl_info = context->gl_info;

    if (!context->transform_feedback_active || context->transform_feedback_paused)
        return;

    if (gl_info->supported[ARB_TRANSFORM_FEEDBACK2])
    {
        GL_EXTCALL(glPauseTransformFeedback());
        checkGLcall("glPauseTransformFeedback");
        context->transform_feedback_paused = 1;
        return;
    }

    WARN("Cannot pause transform feedback operations.\n");

    if (force)
        context_end_transform_feedback(context);
}

483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
static GLenum gl_tfb_primitive_type_from_d3d(enum wined3d_primitive_type primitive_type)
{
    GLenum gl_primitive_type = gl_primitive_type_from_d3d(primitive_type);
    switch (gl_primitive_type)
    {
        case GL_POINTS:
            return GL_POINTS;

        case GL_LINE_STRIP:
        case GL_LINE_STRIP_ADJACENCY:
        case GL_LINES_ADJACENCY:
        case GL_LINES:
            return GL_LINES;

        case GL_TRIANGLE_FAN:
        case GL_TRIANGLE_STRIP:
        case GL_TRIANGLE_STRIP_ADJACENCY:
        case GL_TRIANGLES_ADJACENCY:
        case GL_TRIANGLES:
            return GL_TRIANGLES;

        default:
            return gl_primitive_type;
    }
}

509
/* Routine common to the draw primitive and draw indexed primitive routines */
510
void draw_primitive(struct wined3d_device *device, const struct wined3d_state *state,
511
        const struct wined3d_draw_parameters *parameters)
512
{
513
    BOOL emulation = FALSE, rasterizer_discard = FALSE;
514
    const struct wined3d_fb_state *fb = state->fb;
515
    const struct wined3d_stream_info *stream_info;
516
    struct wined3d_rendertarget_view *dsv, *rtv;
517
    struct wined3d_stream_info si_emulated;
518
    struct wined3d_fence *ib_fence = NULL;
519
    const struct wined3d_gl_info *gl_info;
520
    struct wined3d_context *context;
521
    unsigned int i, idx_size = 0;
522
    const void *idx_data = NULL;
523

524
    if (!parameters->indirect && !parameters->u.direct.index_count)
525
        return;
526

527 528
    if (!(rtv = fb->render_targets[0]))
        rtv = fb->depth_stencil;
529 530 531 532
    if (rtv)
        context = context_acquire(device, wined3d_texture_from_resource(rtv->resource), rtv->sub_resource_idx);
    else
        context = context_acquire(device, NULL, 0);
533 534 535 536 537 538 539 540
    if (!context->valid)
    {
        context_release(context);
        WARN("Invalid context, skipping draw.\n");
        return;
    }
    gl_info = context->gl_info;

541 542
    if (!use_transform_feedback(state))
        context_pause_transform_feedback(context, TRUE);
543

544
    for (i = 0; i < gl_info->limits.buffers; ++i)
545
    {
546
        if (!(rtv = fb->render_targets[i]) || rtv->format->id == WINED3DFMT_NULL)
547 548 549
            continue;

        if (state->render_states[WINED3D_RS_COLORWRITEENABLE])
550
        {
551
            wined3d_rendertarget_view_load_location(rtv, context, rtv->resource->draw_binding);
552
            wined3d_rendertarget_view_invalidate_location(rtv, ~rtv->resource->draw_binding);
553 554 555
        }
        else
        {
556
            wined3d_rendertarget_view_prepare_location(rtv, context, rtv->resource->draw_binding);
557 558 559
        }
    }

560
    if ((dsv = fb->depth_stencil))
561
    {
562
        /* Note that this depends on the context_acquire() call above to set
563
         * context->render_offscreen properly. We don't currently take the
564 565 566
         * Z-compare function into account, but we could skip loading the
         * depthstencil for D3DCMP_NEVER and D3DCMP_ALWAYS as well. Also note
         * that we never copy the stencil data.*/
567
        DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
568

569
        if (state->render_states[WINED3D_RS_ZWRITEENABLE] || state->render_states[WINED3D_RS_ZENABLE])
570
            wined3d_rendertarget_view_load_location(dsv, context, location);
571
        else
572
            wined3d_rendertarget_view_prepare_location(dsv, context, location);
573 574
    }

575
    if (!context_apply_draw_state(context, device, state))
576 577 578 579 580 581
    {
        context_release(context);
        WARN("Unable to apply draw state, skipping draw.\n");
        return;
    }

582
    if (dsv && state->render_states[WINED3D_RS_ZWRITEENABLE])
583
    {
584
        DWORD location = context->render_offscreen ? dsv->resource->draw_binding : WINED3D_LOCATION_DRAWABLE;
585

586
        wined3d_rendertarget_view_validate_location(dsv, location);
587
        wined3d_rendertarget_view_invalidate_location(dsv, ~location);
588 589
    }

590
    stream_info = &context->stream_info;
591

592
    if (parameters->indexed)
593
    {
594 595
        struct wined3d_buffer *index_buffer = state->index_buffer;
        if (!index_buffer->buffer_object || !stream_info->all_vbo)
596
        {
597
            idx_data = index_buffer->resource.heap_memory;
598
        }
599
        else
600
        {
601
            ib_fence = index_buffer->fence;
602
            idx_data = NULL;
603
        }
604
        idx_data = (const BYTE *)idx_data + state->index_offset;
605 606 607 608 609 610

        if (state->index_format == WINED3DFMT_R16_UINT)
            idx_size = 2;
        else
            idx_size = 4;
    }
611

612 613 614 615 616 617 618 619 620
    if (!use_vs(state))
    {
        if (!stream_info->position_transformed && context->num_untracked_materials
                && state->render_states[WINED3D_RS_LIGHTING])
        {
            static BOOL warned;

            if (!warned++)
                FIXME("Using software emulation because not all material properties could be tracked.\n");
621
            else
622
                WARN_(d3d_perf)("Using software emulation because not all material properties could be tracked.\n");
623
            emulation = TRUE;
624
        }
625
        else if (context->fog_coord && state->render_states[WINED3D_RS_FOGENABLE])
626
        {
627
            static BOOL warned;
628

629 630 631 632 633 634
            /* Either write a pipeline replacement shader or convert the
             * specular alpha from unsigned byte to a float in the vertex
             * buffer. */
            if (!warned++)
                FIXME("Using software emulation because manual fog coordinates are provided.\n");
            else
635
                WARN_(d3d_perf)("Using software emulation because manual fog coordinates are provided.\n");
636
            emulation = TRUE;
637 638
        }

639
        if (emulation)
640
        {
641
            si_emulated = context->stream_info;
642
            remove_vbos(context, state, &si_emulated);
643
            stream_info = &si_emulated;
644
        }
645 646
    }

647
    if (use_transform_feedback(state))
648 649 650
    {
        const struct wined3d_shader *shader = state->shader[WINED3D_SHADER_TYPE_GEOMETRY];

651
        if (is_rasterization_disabled(shader))
652 653 654 655 656 657
        {
            glEnable(GL_RASTERIZER_DISCARD);
            checkGLcall("enable rasterizer discard");
            rasterizer_discard = TRUE;
        }

658 659 660 661 662 663 664 665
        if (context->transform_feedback_paused)
        {
            GL_EXTCALL(glResumeTransformFeedback());
            checkGLcall("glResumeTransformFeedback");
            context->transform_feedback_paused = 0;
        }
        else if (!context->transform_feedback_active)
        {
666 667
            GLenum mode = gl_tfb_primitive_type_from_d3d(shader->u.gs.output_type);
            GL_EXTCALL(glBeginTransformFeedback(mode));
668 669 670
            checkGLcall("glBeginTransformFeedback");
            context->transform_feedback_active = 1;
        }
671 672
    }

673 674 675 676 677 678
    if (state->gl_primitive_type == GL_PATCHES)
    {
        GL_EXTCALL(glPatchParameteri(GL_PATCH_VERTICES, state->gl_patch_vertices));
        checkGLcall("glPatchParameteri");
    }

679 680 681
    if (parameters->indirect)
    {
        if (!context->use_immediate_mode_draw && !emulation)
682
            draw_indirect(context, state, &parameters->u.indirect, idx_size);
683 684 685
        else
            FIXME("Indirect draws with immediate mode/emulation are not supported.\n");
    }
686
    else
687 688 689 690 691 692 693 694 695 696 697 698 699 700
    {
        unsigned int instance_count = parameters->u.direct.instance_count;
        if (context->instance_count)
            instance_count = context->instance_count;

        if (context->use_immediate_mode_draw || emulation)
            draw_primitive_immediate_mode(context, state, stream_info, idx_data,
                    idx_size, parameters->u.direct.base_vertex_idx,
                    parameters->u.direct.start_idx, parameters->u.direct.index_count, instance_count);
        else
            draw_primitive_arrays(context, state, idx_data, idx_size, parameters->u.direct.base_vertex_idx,
                    parameters->u.direct.start_idx, parameters->u.direct.index_count,
                    parameters->u.direct.start_instance, instance_count);
    }
701

702 703 704 705 706 707
    if (context->uses_uavs)
    {
        GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
        checkGLcall("glMemoryBarrier");
    }

708
    context_pause_transform_feedback(context, FALSE);
709

710 711 712 713 714 715
    if (rasterizer_discard)
    {
        glDisable(GL_RASTERIZER_DISCARD);
        checkGLcall("disable rasterizer discard");
    }

716 717 718 719
    if (ib_fence)
        wined3d_fence_issue(ib_fence, device);
    for (i = 0; i < context->buffer_fence_count; ++i)
        wined3d_fence_issue(context->buffer_fences[i], device);
720

721 722
    if (wined3d_settings.strict_draw_ordering)
        gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
723

724 725
    context_release(context);

726
    TRACE("Done all gl drawing.\n");
727
}
728 729

void dispatch_compute(struct wined3d_device *device, const struct wined3d_state *state,
730
        const struct wined3d_dispatch_parameters *parameters)
731 732 733 734
{
    const struct wined3d_gl_info *gl_info;
    struct wined3d_context *context;

735
    context = context_acquire(device, NULL, 0);
736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
    if (!context->valid)
    {
        context_release(context);
        WARN("Invalid context, skipping dispatch.\n");
        return;
    }
    gl_info = context->gl_info;

    if (!gl_info->supported[ARB_COMPUTE_SHADER])
    {
        context_release(context);
        FIXME("OpenGL implementation does not support compute shaders.\n");
        return;
    }

    context_apply_compute_state(context, device, state);

    if (!state->shader[WINED3D_SHADER_TYPE_COMPUTE])
    {
        context_release(context);
        WARN("No compute shader bound, skipping dispatch.\n");
        return;
    }

760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775
    if (parameters->indirect)
    {
        const struct wined3d_indirect_dispatch_parameters *indirect = &parameters->u.indirect;
        struct wined3d_buffer *buffer = indirect->buffer;

        wined3d_buffer_load(buffer, context, state);
        GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, buffer->buffer_object));
        GL_EXTCALL(glDispatchComputeIndirect((GLintptr)indirect->offset));
        GL_EXTCALL(glBindBuffer(GL_DISPATCH_INDIRECT_BUFFER, 0));
    }
    else
    {
        const struct wined3d_direct_dispatch_parameters *direct = &parameters->u.direct;
        GL_EXTCALL(glDispatchCompute(direct->group_count_x, direct->group_count_y, direct->group_count_z));
    }
    checkGLcall("dispatch compute");
776 777 778 779 780 781 782 783 784

    GL_EXTCALL(glMemoryBarrier(GL_ALL_BARRIER_BITS));
    checkGLcall("glMemoryBarrier");

    if (wined3d_settings.strict_draw_ordering)
        gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */

    context_release(context);
}