Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/canvas/WebGL2ContextBuffers.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "WebGL2Context.h"
7
8
#include "GLContext.h"
9
#include "WebGLBuffer.h"
10
#include "WebGLTransformFeedback.h"
11
12
namespace mozilla {
13
14
// -------------------------------------------------------------------------
15
// Buffer objects
16
17
void
18
WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
19
                                 GLintptr readOffset, GLintptr writeOffset,
20
                                 GLsizeiptr size)
21
0
{
22
0
    const FuncScope funcScope(*this, "copyBufferSubData");
23
0
    if (IsContextLost())
24
0
        return;
25
0
26
0
    const auto& readBuffer = ValidateBufferSelection(readTarget);
27
0
    if (!readBuffer)
28
0
        return;
29
0
30
0
    const auto& writeBuffer = ValidateBufferSelection(writeTarget);
31
0
    if (!writeBuffer)
32
0
        return;
33
0
34
0
    if (!ValidateNonNegative("readOffset", readOffset) ||
35
0
        !ValidateNonNegative("writeOffset", writeOffset) ||
36
0
        !ValidateNonNegative("size", size))
37
0
    {
38
0
        return;
39
0
    }
40
0
41
0
    const auto fnValidateOffsetSize = [&](const char* info, GLintptr offset,
42
0
                                          const WebGLBuffer* buffer)
43
0
    {
44
0
        const auto neededBytes = CheckedInt<size_t>(offset) + size;
45
0
        if (!neededBytes.isValid() || neededBytes.value() > buffer->ByteLength()) {
46
0
            ErrorInvalidValue("Invalid %s range.", info);
47
0
            return false;
48
0
        }
49
0
        return true;
50
0
    };
51
0
52
0
    if (!fnValidateOffsetSize("read", readOffset, readBuffer) ||
53
0
        !fnValidateOffsetSize("write", writeOffset, writeBuffer))
54
0
    {
55
0
        return;
56
0
    }
57
0
58
0
    if (readBuffer == writeBuffer) {
59
0
        MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
60
0
        MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
61
0
62
0
        const bool separate = (readOffset + size <= writeOffset ||
63
0
                               writeOffset + size <= readOffset);
64
0
        if (!separate) {
65
0
            ErrorInvalidValue("Ranges [readOffset, readOffset + size) and"
66
0
                              " [writeOffset, writeOffset + size) overlap.");
67
0
            return;
68
0
        }
69
0
    }
70
0
71
0
    const auto& readType = readBuffer->Content();
72
0
    const auto& writeType = writeBuffer->Content();
73
0
    MOZ_ASSERT(readType != WebGLBuffer::Kind::Undefined);
74
0
    MOZ_ASSERT(writeType != WebGLBuffer::Kind::Undefined);
75
0
    if (writeType != readType) {
76
0
        ErrorInvalidOperation("Can't copy %s data to %s data.",
77
0
                              (readType == WebGLBuffer::Kind::OtherData) ? "other"
78
0
                                                                         : "element",
79
0
                              (writeType == WebGLBuffer::Kind::OtherData) ? "other"
80
0
                                                                          : "element");
81
0
        return;
82
0
    }
83
0
84
0
    const ScopedLazyBind readBind(gl, readTarget, readBuffer);
85
0
    const ScopedLazyBind writeBind(gl, writeTarget, writeBuffer);
86
0
    gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
87
0
88
0
    writeBuffer->ResetLastUpdateFenceId();
89
0
}
90
91
void
92
WebGL2Context::GetBufferSubData(GLenum target, GLintptr srcByteOffset,
93
                                const dom::ArrayBufferView& dstData, GLuint dstElemOffset,
94
                                GLuint dstElemCountOverride)
95
0
{
96
0
    const FuncScope funcScope(*this, "getBufferSubData");
97
0
    if (IsContextLost())
98
0
        return;
99
0
100
0
    if (!ValidateNonNegative("srcByteOffset", srcByteOffset))
101
0
        return;
102
0
103
0
    uint8_t* bytes;
104
0
    size_t byteLen;
105
0
    if (!ValidateArrayBufferView(dstData, dstElemOffset, dstElemCountOverride,
106
0
                                 &bytes, &byteLen))
107
0
    {
108
0
        return;
109
0
    }
110
0
111
0
    ////
112
0
113
0
    const auto& buffer = ValidateBufferSelection(target);
114
0
    if (!buffer)
115
0
        return;
116
0
117
0
    if (!buffer->ValidateRange(srcByteOffset, byteLen))
118
0
        return;
119
0
120
0
    ////
121
0
122
0
    if (!CheckedInt<GLsizeiptr>(byteLen).isValid()) {
123
0
        ErrorOutOfMemory("Size too large.");
124
0
        return;
125
0
    }
126
0
    const GLsizeiptr glByteLen(byteLen);
127
0
128
0
    ////
129
0
130
0
    switch (buffer->mUsage) {
131
0
    case LOCAL_GL_STATIC_READ:
132
0
    case LOCAL_GL_STREAM_READ:
133
0
    case LOCAL_GL_DYNAMIC_READ:
134
0
        if (mCompletedFenceId < buffer->mLastUpdateFenceId) {
135
0
            GenerateWarning("Reading from a buffer without checking for previous"
136
0
                            " command completion likely causes pipeline stalls."
137
0
                            " Please use FenceSync.");
138
0
        }
139
0
        break;
140
0
    default:
141
0
        GenerateWarning("Reading from a buffer with usage other than *_READ"
142
0
                        " causes pipeline stalls. Copy through a STREAM_READ buffer.");
143
0
        break;
144
0
    }
145
0
146
0
    ////
147
0
148
0
    const ScopedLazyBind readBind(gl, target, buffer);
149
0
150
0
    if (byteLen) {
151
0
        const bool isTF = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
152
0
        GLenum mapTarget = target;
153
0
        if (isTF) {
154
0
            gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, mEmptyTFO);
155
0
            gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, buffer->mGLName);
156
0
            mapTarget = LOCAL_GL_ARRAY_BUFFER;
157
0
        }
158
0
159
0
        const auto mappedBytes = gl->fMapBufferRange(mapTarget, srcByteOffset, glByteLen,
160
0
                                                     LOCAL_GL_MAP_READ_BIT);
161
0
        memcpy(bytes, mappedBytes, byteLen);
162
0
        gl->fUnmapBuffer(mapTarget);
163
0
164
0
        if (isTF) {
165
0
            const GLuint vbo = (mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0);
166
0
            gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, vbo);
167
0
            const GLuint tfo = (mBoundTransformFeedback ? mBoundTransformFeedback->mGLName
168
0
                                                        : 0);
169
0
            gl->fBindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tfo);
170
0
        }
171
0
    }
172
0
}
173
174
} // namespace mozilla