summaryrefslogtreecommitdiffstats
path: root/dom/canvas/WebGL2ContextBuffers.cpp
blob: f59fa08b836e50deefdbf5e512c6cce869716bbd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "WebGL2Context.h"

#include "GLContext.h"
#include "WebGLBuffer.h"
#include "WebGLTransformFeedback.h"

namespace mozilla {

// -------------------------------------------------------------------------
// Buffer objects

void
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                                 GLintptr readOffset, GLintptr writeOffset,
                                 GLsizeiptr size)
{
    const char funcName[] = "copyBufferSubData";
    if (IsContextLost())
        return;

    const auto& readBuffer = ValidateBufferSelection(funcName, readTarget);
    if (!readBuffer)
        return;

    const auto& writeBuffer = ValidateBufferSelection(funcName, writeTarget);
    if (!writeBuffer)
        return;

    if (!ValidateNonNegative(funcName, "readOffset", readOffset) ||
        !ValidateNonNegative(funcName, "writeOffset", writeOffset) ||
        !ValidateNonNegative(funcName, "size", size))
    {
        return;
    }

    const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
                                          const WebGLBuffer* buffer)
    {
        const auto neededBytes = CheckedInt<size_t>(offset) + size;
        if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
            ErrorInvalidValue("%s: Invalid %s range.", funcName, info);
            return false;
        }
        return true;
    };

    if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
        !fnValidateOffsetSize("write", writeOffset, writeBuffer))
    {
        return;
    }

    if (readBuffer == writeBuffer) {
        MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
        MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());

        const bool separate = (readOffset + size <= writeOffset ||
                               writeOffset + size <= readOffset);
        if (!separate) {
            ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and"
                              " [writeOffset, writeOffset + size) overlap",
                              funcName);
            return;
        }
    }

    const auto& readType = readBuffer->Content();
    const auto& writeType = writeBuffer->Content();
    MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
    MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
    if (writeType != readType) {
        ErrorInvalidOperation("%s: Can't copy %s data to %s data.",
                              funcName,
                              (readType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                         : "element",
                              (writeType == WebGLBuffer::Kind::OtherData) ? "other"
                                                                          : "element");
        return;
    }

    gl->MakeCurrent();
    const ScopedLazyBind readBind(gl, readTarget, readBuffer);
    const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
    gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
}

void
WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
                                const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
                                GLuint dstElemCountOverride)
{
    const char funcName[] = "getBufferSubData";
    if (IsContextLost())
        return;

    if (!ValidateNonNegative(funcName, "srcByteOffset", srcByteOffset))
        return;

    uint8_t* bytes;
    size_t byteLen;
    if (!ValidateArrayBufferView(funcName, dstData, dstElemOffset, dstElemCountOverride,
                                 &bytes, &byteLen))
    {
        return;
    }

    ////

    const auto& buffer = ValidateBufferSelection(funcName, target);
    if (!buffer)
        return;

    if (!buffer->ValidateRange(funcName, srcByteOffset, byteLen))
        return;

    ////

    if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
        ErrorOutOfMemory("%s: Size too large.", funcName);
        return;
    }
    const GLsizeiptr glByteLen(byteLen);

    ////

    gl->MakeCurrent();
    const ScopedLazyBind readBind(gl, target, buffer);

    if (byteLen) {
        const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
        GLenum mapTarget = target;
        if (isTF) {
            gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
            gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
            mapTarget = LOCAL_GL_ARRAY_BUFFER;
        }

        const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
                                                     LOCAL_GL_MAP_READ_BIT);
        memcpy(bytes, mappedBytes, byteLen);
        gl->fUnmapBuffer(mapTarget);

        if (isTF) {
            const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
            gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
            const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
                                                        : 0);
            gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
        }
    }
}

} // namespace mozilla