Hash :
e12bb29c
Author :
Date :
2025-08-01T15:34:26
Recompute vertex capacity when resuming transform feedback. Extract vertex capacity computation into recomputeVertexCapacity() and call it from both begin() and resume() to handle cases where the backing buffer size changes while transform feedback is paused. Add a new WebGL specific test to TransformFeedback to test the expected behavior when making the backing buffer smaller via glBufferData. Bug: angleproject:437706201 Change-Id: I3ac8e1e983ab868e34c1bdac249ce17a40e274f0 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/6830709 Reviewed-by: Charlie Lao <cclao@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Kimmo Kinnunen <kkinnunen@apple.com>
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
//
// Copyright 2014 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
#ifndef LIBANGLE_TRANSFORM_FEEDBACK_H_
#define LIBANGLE_TRANSFORM_FEEDBACK_H_
#include "libANGLE/RefCountObject.h"
#include "common/PackedEnums.h"
#include "common/angleutils.h"
#include "libANGLE/Debug.h"
#include "angle_gl.h"
namespace rx
{
class GLImplFactory;
class TransformFeedbackImpl;
class TransformFeedbackGL;
} // namespace rx
namespace gl
{
class Buffer;
struct Caps;
class Context;
class Program;
class TransformFeedbackState final : angle::NonCopyable
{
public:
TransformFeedbackState(size_t maxIndexedBuffers);
~TransformFeedbackState();
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t idx) const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
const Program *getBoundProgram() const { return mProgram; }
GLsizeiptr getVerticesDrawn() const { return mVerticesDrawn; }
GLsizeiptr getPrimitivesDrawn() const;
private:
friend class TransformFeedback;
std::string mLabel;
bool mActive;
PrimitiveMode mPrimitiveMode;
bool mPaused;
GLsizeiptr mVerticesDrawn;
GLsizeiptr mVertexCapacity;
Program *mProgram;
std::vector<OffsetBindingPointer<Buffer>> mIndexedBuffers;
};
class TransformFeedback final : public RefCountObject<TransformFeedbackID>, public LabeledObject
{
public:
TransformFeedback(rx::GLImplFactory *implFactory, TransformFeedbackID id, const Caps &caps);
~TransformFeedback() override;
void onDestroy(const Context *context) override;
angle::Result setLabel(const Context *context, const std::string &label) override;
const std::string &getLabel() const override;
angle::Result begin(const Context *context, PrimitiveMode primitiveMode, Program *program);
angle::Result end(const Context *context);
angle::Result pause(const Context *context);
angle::Result resume(const Context *context);
bool isActive() const { return mState.mActive; }
bool isPaused() const;
PrimitiveMode getPrimitiveMode() const;
// Validates that the vertices produced by a draw call will fit in the bound transform feedback
// buffers.
bool checkBufferSpaceForDraw(GLsizei count, GLsizei primcount) const;
// This must be called after each draw call when transform feedback is enabled to keep track of
// how many vertices have been written to the buffers. This information is needed by
// checkBufferSpaceForDraw because each draw call appends vertices to the buffers starting just
// after the last vertex of the previous draw call.
void onVerticesDrawn(const Context *context, GLsizei count, GLsizei primcount);
bool hasBoundProgram(ShaderProgramID program) const;
angle::Result bindIndexedBuffer(const Context *context,
size_t index,
Buffer *buffer,
size_t offset,
size_t size);
const OffsetBindingPointer<Buffer> &getIndexedBuffer(size_t index) const;
size_t getIndexedBufferCount() const;
const std::vector<OffsetBindingPointer<Buffer>> &getIndexedBuffers() const;
GLsizeiptr getVerticesDrawn() const { return mState.getVerticesDrawn(); }
GLsizeiptr getPrimitivesDrawn() const { return mState.getPrimitivesDrawn(); }
// Returns true if any buffer bound to this object is also bound to another target.
bool buffersBoundForOtherUseInWebGL() const;
// Returns true if the buffer is bound to any of the indexed binding points in this transform
// feedback.
bool isBufferBound(BufferID bufferID) const;
angle::Result detachBuffer(const Context *context, BufferID bufferID);
rx::TransformFeedbackImpl *getImplementation() const { return mImplementation; }
void onBindingChanged(const Context *context, bool bound);
private:
void bindProgram(const Context *context, Program *program);
void recomputeVertexCapacity(const Context *context);
TransformFeedbackState mState;
rx::TransformFeedbackImpl *mImplementation;
};
} // namespace gl
#endif // LIBANGLE_TRANSFORM_FEEDBACK_H_