gecko-dev/dom/canvas/WebGLBuffer.h
Jamie Nicol 942a3f5367 Bug 1826134 - Avoid interleaving glBufferSubData calls with draw calls in DrawTargetWebgl. r=gfx-reviewers,jgilbert,lsalzman
DrawTargetWebgl renders a path by uploading vertex data to the back of
a large VBO using glBufferSubData then issuing a draw call, orphaning
the buffer when it becomes full. This results in many glBufferSubData
calls being interleaved with draw calls. On Mali GPUs this causes
severe performance issues as the driver is unable to determine that
any pending draw calls do not reference the updated region of the
buffer, and therefore must create a copy of the buffer for each
update.

However, since *we* know that we never overwrite a region that is
referenced by a submitted draw call, we can force the driver to avoid
making these copies. We do so by adding a new function
UnsynchronizedBufferSubData(), which acts like BufferSubData so long
as this rule is followed. Internally, this uses glMapBufferRange with
GL_MAP_UNSYNCHRONIZED_BIT, allowing the driver to omit the extraneous
copies.

Differential Revision: https://phabricator.services.mozilla.com/D174685
2023-04-07 07:25:50 +00:00

88 lines
2.4 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#ifndef WEBGL_BUFFER_H_
#define WEBGL_BUFFER_H_
#include <map>
#include "CacheInvalidator.h"
#include "GLDefs.h"
#include "WebGLObjectModel.h"
#include "WebGLTypes.h"
namespace mozilla {
class WebGLBuffer final : public WebGLContextBoundObject {
friend class WebGLContext;
friend class WebGL2Context;
friend class WebGLMemoryTracker;
friend class WebGLTexture;
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(WebGLBuffer, override)
public:
enum class Kind { Undefined, ElementArray, OtherData };
WebGLBuffer(WebGLContext* webgl, GLuint buf);
void SetContentAfterBind(GLenum target);
Kind Content() const { return mContent; }
size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
GLenum Usage() const { return mUsage; }
size_t ByteLength() const { return mByteLength; }
Maybe<uint32_t> GetIndexedFetchMaxVert(GLenum type, uint64_t byteOffset,
uint32_t indexCount) const;
bool ValidateRange(size_t byteOffset, size_t byteLen) const;
bool ValidateCanBindToTarget(GLenum target);
void BufferData(GLenum target, uint64_t size, const void* data, GLenum usage);
void BufferSubData(GLenum target, uint64_t dstByteOffset, uint64_t dataLen,
const void* data, bool unsynchronized = false) const;
////
const GLenum mGLName;
protected:
~WebGLBuffer() override;
void InvalidateCacheRange(uint64_t byteOffset, uint64_t byteLength) const;
Kind mContent = Kind::Undefined;
GLenum mUsage = LOCAL_GL_STATIC_DRAW;
size_t mByteLength = 0;
mutable uint64_t mLastUpdateFenceId = 0;
struct IndexRange final {
GLenum type;
uint64_t byteOffset;
uint32_t indexCount;
bool operator<(const IndexRange& x) const {
if (type != x.type) return type < x.type;
if (byteOffset != x.byteOffset) return byteOffset < x.byteOffset;
return indexCount < x.indexCount;
}
};
UniqueBuffer mIndexCache;
mutable std::map<IndexRange, Maybe<uint32_t>> mIndexRanges;
public:
CacheInvalidator mFetchInvalidator;
void ResetLastUpdateFenceId() const;
};
} // namespace mozilla
#endif // WEBGL_BUFFER_H_