CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/GPU/GLES/DrawEngineGLES.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617#include <algorithm>1819#include "Common/LogReporting.h"20#include "Common/MemoryUtil.h"21#include "Common/TimeUtil.h"22#include "Core/MemMap.h"23#include "Core/System.h"24#include "Core/Config.h"25#include "Core/CoreTiming.h"2627#include "Common/GPU/OpenGL/GLDebugLog.h"28#include "Common/Profiler/Profiler.h"2930#include "GPU/Math3D.h"31#include "GPU/GPUState.h"32#include "GPU/ge_constants.h"3334#include "GPU/Common/TextureDecoder.h"35#include "GPU/Common/SplineCommon.h"36#include "GPU/Common/VertexDecoderCommon.h"37#include "GPU/Common/SoftwareTransformCommon.h"38#include "GPU/Debugger/Debugger.h"39#include "GPU/GLES/FragmentTestCacheGLES.h"40#include "GPU/GLES/StateMappingGLES.h"41#include "GPU/GLES/TextureCacheGLES.h"42#include "GPU/GLES/DrawEngineGLES.h"43#include "GPU/GLES/ShaderManagerGLES.h"44#include "GPU/GLES/GPU_GLES.h"4546static const GLuint glprim[8] = {47// Points, which are expanded to triangles.48GL_TRIANGLES,49// Lines and line strips, which are also expanded to triangles.50GL_TRIANGLES,51GL_TRIANGLES,52GL_TRIANGLES,53GL_TRIANGLE_STRIP,54GL_TRIANGLE_FAN,55// Rectangles, which are expanded to triangles.56GL_TRIANGLES,57};5859enum {60TRANSFORMED_VERTEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * sizeof(TransformedVertex)61};6263DrawEngineGLES::DrawEngineGLES(Draw::DrawContext *draw) : inputLayoutMap_(16), draw_(draw) {64render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);6566decOptions_.expandAllWeightsToFloat = false;67decOptions_.expand8BitNormalsToFloat = false;6869indexGen.Setup(decIndex_);7071InitDeviceObjects();7273tessDataTransferGLES = new TessellationDataTransferGLES(render_);74tessDataTransfer = tessDataTransferGLES;75}7677DrawEngineGLES::~DrawEngineGLES() {78DestroyDeviceObjects();7980delete tessDataTransferGLES;81}8283void DrawEngineGLES::DeviceLost() {84DestroyDeviceObjects();85draw_ = nullptr;86render_ = nullptr;87}8889void DrawEngineGLES::DeviceRestore(Draw::DrawContext *draw) {90draw_ = draw;91render_ = (GLRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER);92InitDeviceObjects();93}9495void DrawEngineGLES::InitDeviceObjects() {96_assert_msg_(render_ != nullptr, "Render manager must be set");9798for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {99frameData_[i].pushVertex = render_->CreatePushBuffer(i, GL_ARRAY_BUFFER, 2048 * 1024, "game_vertex");100frameData_[i].pushIndex = render_->CreatePushBuffer(i, GL_ELEMENT_ARRAY_BUFFER, 256 * 1024, "game_index");101}102103int stride = sizeof(TransformedVertex);104std::vector<GLRInputLayout::Entry> entries;105entries.push_back({ ATTR_POSITION, 4, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, x) });106entries.push_back({ ATTR_TEXCOORD, 3, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, u) });107entries.push_back({ ATTR_COLOR0, 4, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(TransformedVertex, color0) });108entries.push_back({ ATTR_COLOR1, 3, GL_UNSIGNED_BYTE, GL_TRUE, offsetof(TransformedVertex, color1) });109entries.push_back({ ATTR_NORMAL, 1, GL_FLOAT, GL_FALSE, offsetof(TransformedVertex, fog) });110softwareInputLayout_ = render_->CreateInputLayout(entries, stride);111112draw_->SetInvalidationCallback(std::bind(&DrawEngineGLES::Invalidate, this, std::placeholders::_1));113}114115void DrawEngineGLES::DestroyDeviceObjects() {116if (!draw_) {117return;118}119draw_->SetInvalidationCallback(InvalidationCallback());120121// Beware: this could be called twice in a row, sometimes.122for (int i = 0; i < GLRenderManager::MAX_INFLIGHT_FRAMES; i++) {123if (!frameData_[i].pushVertex && !frameData_[i].pushIndex)124continue;125126if (frameData_[i].pushVertex)127render_->DeletePushBuffer(frameData_[i].pushVertex);128if (frameData_[i].pushIndex)129render_->DeletePushBuffer(frameData_[i].pushIndex);130frameData_[i].pushVertex = nullptr;131frameData_[i].pushIndex = nullptr;132}133134ClearTrackedVertexArrays();135136if (softwareInputLayout_)137render_->DeleteInputLayout(softwareInputLayout_);138softwareInputLayout_ = nullptr;139140ClearInputLayoutMap();141}142143void DrawEngineGLES::ClearInputLayoutMap() {144inputLayoutMap_.Iterate([&](const uint32_t &key, GLRInputLayout *il) {145render_->DeleteInputLayout(il);146});147inputLayoutMap_.Clear();148}149150void DrawEngineGLES::BeginFrame() {151FrameData &frameData = frameData_[render_->GetCurFrame()];152frameData.pushIndex->Begin();153frameData.pushVertex->Begin();154155lastRenderStepId_ = -1;156}157158void DrawEngineGLES::EndFrame() {159FrameData &frameData = frameData_[render_->GetCurFrame()];160frameData.pushIndex->End();161frameData.pushVertex->End();162tessDataTransferGLES->EndFrame();163}164165struct GlTypeInfo {166u16 type;167u8 count;168u8 normalized;169};170171static const GlTypeInfo GLComp[] = {172{0}, // DEC_NONE,173{GL_FLOAT, 1, GL_FALSE}, // DEC_FLOAT_1,174{GL_FLOAT, 2, GL_FALSE}, // DEC_FLOAT_2,175{GL_FLOAT, 3, GL_FALSE}, // DEC_FLOAT_3,176{GL_FLOAT, 4, GL_FALSE}, // DEC_FLOAT_4,177{GL_BYTE, 4, GL_TRUE}, // DEC_S8_3,178{GL_SHORT, 4, GL_TRUE},// DEC_S16_3,179{GL_UNSIGNED_BYTE, 1, GL_TRUE},// DEC_U8_1,180{GL_UNSIGNED_BYTE, 2, GL_TRUE},// DEC_U8_2,181{GL_UNSIGNED_BYTE, 3, GL_TRUE},// DEC_U8_3,182{GL_UNSIGNED_BYTE, 4, GL_TRUE},// DEC_U8_4,183{GL_UNSIGNED_SHORT, 1, GL_TRUE},// DEC_U16_1,184{GL_UNSIGNED_SHORT, 2, GL_TRUE},// DEC_U16_2,185{GL_UNSIGNED_SHORT, 3, GL_TRUE},// DEC_U16_3,186{GL_UNSIGNED_SHORT, 4, GL_TRUE},// DEC_U16_4,187};188189static inline void VertexAttribSetup(int attrib, int fmt, int offset, std::vector<GLRInputLayout::Entry> &entries) {190if (fmt) {191const GlTypeInfo &type = GLComp[fmt];192GLRInputLayout::Entry entry;193entry.offset = offset;194entry.location = attrib;195entry.normalized = type.normalized;196entry.type = type.type;197entry.count = type.count;198entries.push_back(entry);199}200}201202// TODO: Use VBO and get rid of the vertexData pointers - with that, we will supply only offsets203GLRInputLayout *DrawEngineGLES::SetupDecFmtForDraw(const DecVtxFormat &decFmt) {204uint32_t key = decFmt.id;205GLRInputLayout *inputLayout;206if (inputLayoutMap_.Get(key, &inputLayout)) {207return inputLayout;208}209210std::vector<GLRInputLayout::Entry> entries;211VertexAttribSetup(ATTR_W1, decFmt.w0fmt, decFmt.w0off, entries);212VertexAttribSetup(ATTR_W2, decFmt.w1fmt, decFmt.w1off, entries);213VertexAttribSetup(ATTR_TEXCOORD, decFmt.uvfmt, decFmt.uvoff, entries);214VertexAttribSetup(ATTR_COLOR0, decFmt.c0fmt, decFmt.c0off, entries);215VertexAttribSetup(ATTR_COLOR1, decFmt.c1fmt, decFmt.c1off, entries);216VertexAttribSetup(ATTR_NORMAL, decFmt.nrmfmt, decFmt.nrmoff, entries);217VertexAttribSetup(ATTR_POSITION, DecVtxFormat::PosFmt(), decFmt.posoff, entries);218219int stride = decFmt.stride;220inputLayout = render_->CreateInputLayout(entries, stride);221inputLayoutMap_.Insert(key, inputLayout);222return inputLayout;223}224225// A new render step means we need to flush any dynamic state. Really, any state that is reset in226// GLQueueRunner::PerformRenderPass.227void DrawEngineGLES::Invalidate(InvalidationCallbackFlags flags) {228if (flags & InvalidationCallbackFlags::RENDER_PASS_STATE) {229// Dirty everything that has dynamic state that will need re-recording.230gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);231}232}233234void DrawEngineGLES::DoFlush() {235PROFILE_THIS_SCOPE("flush");236FrameData &frameData = frameData_[render_->GetCurFrame()];237VShaderID vsid;238239if (!render_->IsInRenderPass()) {240// Something went badly wrong. Try to survive by simply skipping the draw, though.241_dbg_assert_msg_(false, "Trying to DoFlush while not in a render pass. This is bad.");242// can't goto bail here, skips too many variable initializations. So let's wipe the most important stuff.243indexGen.Reset();244numDecodedVerts_ = 0;245numDrawVerts_ = 0;246numDrawInds_ = 0;247vertexCountInDrawCalls_ = 0;248decodeVertsCounter_ = 0;249decodeIndsCounter_ = 0;250return;251}252253bool textureNeedsApply = false;254if (gstate_c.IsDirty(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS) && !gstate.isModeClear() && gstate.isTextureMapEnabled()) {255textureCache_->SetTexture();256gstate_c.Clean(DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS);257textureNeedsApply = true;258} else if (gstate.getTextureAddress(0) == (gstate.getFrameBufRawAddress() | 0x04000000)) {259// This catches the case of clearing a texture. (#10957)260gstate_c.Dirty(DIRTY_TEXTURE_IMAGE);261}262263GEPrimitiveType prim = prevPrim_;264265Shader *vshader = shaderManager_->ApplyVertexShader(CanUseHardwareTransform(prim), useHWTessellation_, dec_, decOptions_.expandAllWeightsToFloat, decOptions_.applySkinInDecode || !CanUseHardwareTransform(prim), &vsid);266267GLRBuffer *vertexBuffer = nullptr;268GLRBuffer *indexBuffer = nullptr;269uint32_t vertexBufferOffset = 0;270uint32_t indexBufferOffset = 0;271272if (vshader->UseHWTransform()) {273if (decOptions_.applySkinInDecode && (lastVType_ & GE_VTYPE_WEIGHT_MASK)) {274// If software skinning, we're predecoding into "decoded". So make sure we're done, then push that content.275DecodeVerts(decoded_);276uint32_t size = numDecodedVerts_ * dec_->GetDecVtxFmt().stride;277u8 *dest = (u8 *)frameData.pushVertex->Allocate(size, 4, &vertexBuffer, &vertexBufferOffset);278memcpy(dest, decoded_, size);279} else {280// Figure out how much pushbuffer space we need to allocate.281int vertsToDecode = ComputeNumVertsToDecode();282u8 *dest = (u8 *)frameData.pushVertex->Allocate(vertsToDecode * dec_->GetDecVtxFmt().stride, 4, &vertexBuffer, &vertexBufferOffset);283DecodeVerts(dest);284}285286int vertexCount;287int maxIndex;288bool useElements;289DecodeVerts(decoded_);290DecodeIndsAndGetData(&prim, &vertexCount, &maxIndex, &useElements, false);291292if (useElements) {293uint32_t esz = sizeof(uint16_t) * vertexCount;294void *dest = frameData.pushIndex->Allocate(esz, 2, &indexBuffer, &indexBufferOffset);295// TODO: When we need to apply an index offset, we can apply it directly when copying the indices here.296// Of course, minding the maximum value of 65535...297memcpy(dest, decIndex_, esz);298}299300bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;301if (gstate.isModeThrough()) {302gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);303} else {304gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);305}306307if (textureNeedsApply) {308textureCache_->ApplyTexture();309}310311// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.312ApplyDrawState(prim);313ApplyDrawStateLate(false, 0);314315LinkedShader *program = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());316GLRInputLayout *inputLayout = SetupDecFmtForDraw(dec_->GetDecVtxFmt());317if (useElements) {318render_->DrawIndexed(inputLayout,319vertexBuffer, vertexBufferOffset,320indexBuffer, indexBufferOffset,321glprim[prim], vertexCount, GL_UNSIGNED_SHORT);322} else {323render_->Draw(324inputLayout, vertexBuffer, vertexBufferOffset,325glprim[prim], 0, vertexCount);326}327} else {328PROFILE_THIS_SCOPE("soft");329if (!decOptions_.applySkinInDecode) {330decOptions_.applySkinInDecode = true;331lastVType_ |= (1 << 26);332dec_ = GetVertexDecoder(lastVType_);333}334DecodeVerts(decoded_);335int vertexCount = DecodeInds();336337bool hasColor = (lastVType_ & GE_VTYPE_COL_MASK) != GE_VTYPE_COL_NONE;338if (gstate.isModeThrough()) {339gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && (hasColor || gstate.getMaterialAmbientA() == 255);340} else {341gstate_c.vertexFullAlpha = gstate_c.vertexFullAlpha && ((hasColor && (gstate.materialupdate & 1)) || gstate.getMaterialAmbientA() == 255) && (!gstate.isLightingEnabled() || gstate.getAmbientA() == 255);342}343344gpuStats.numUncachedVertsDrawn += vertexCount;345prim = IndexGenerator::GeneralPrim((GEPrimitiveType)drawInds_[0].prim);346347u16 *inds = decIndex_;348SoftwareTransformResult result{};349// TODO: Keep this static? Faster than repopulating?350SoftwareTransformParams params{};351params.decoded = decoded_;352params.transformed = transformed_;353params.transformedExpanded = transformedExpanded_;354params.fbman = framebufferManager_;355params.texCache = textureCache_;356params.allowClear = true; // Clear in OpenGL respects scissor rects, so we'll use it.357params.allowSeparateAlphaClear = true;358params.flippedY = framebufferManager_->UseBufferedRendering();359params.usesHalfZ = false;360361// We need correct viewport values in gstate_c already.362if (gstate_c.IsDirty(DIRTY_VIEWPORTSCISSOR_STATE)) {363ConvertViewportAndScissor(framebufferManager_->UseBufferedRendering(),364framebufferManager_->GetRenderWidth(), framebufferManager_->GetRenderHeight(),365framebufferManager_->GetTargetBufferWidth(), framebufferManager_->GetTargetBufferHeight(),366vpAndScissor_);367UpdateCachedViewportState(vpAndScissor_);368}369370int maxIndex = numDecodedVerts_;371372// TODO: Split up into multiple draw calls for GLES 2.0 where you can't guarantee support for more than 0x10000 verts.373if (gl_extensions.IsGLES && !gl_extensions.GLES3) {374constexpr int vertexCountLimit = 0x10000 / 3;375if (vertexCount > vertexCountLimit) {376WARN_LOG_REPORT_ONCE(manyVerts, Log::G3D, "Truncating vertex count from %d to %d", vertexCount, vertexCountLimit);377vertexCount = vertexCountLimit;378}379}380381SoftwareTransform swTransform(params);382383const Lin::Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset);384const Lin::Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale);385const bool invertedY = gstate_c.vpHeight * (params.flippedY ? 1.0 : -1.0f) < 0;386swTransform.SetProjMatrix(gstate.projMatrix, gstate_c.vpWidth < 0, invertedY, trans, scale);387388swTransform.Transform(prim, dec_->VertexType(), dec_->GetDecVtxFmt(), numDecodedVerts_, &result);389// Non-zero depth clears are unusual, but some drivers don't match drawn depth values to cleared values.390// Games sometimes expect exact matches (see #12626, for example) for equal comparisons.391if (result.action == SW_CLEAR && everUsedEqualDepth_ && gstate.isClearModeDepthMask() && result.depth > 0.0f && result.depth < 1.0f)392result.action = SW_NOT_READY;393394if (textureNeedsApply) {395gstate_c.pixelMapped = result.pixelMapped;396textureCache_->ApplyTexture();397gstate_c.pixelMapped = false;398}399400// Need to ApplyDrawState after ApplyTexture because depal can launch a render pass and that wrecks the state.401ApplyDrawState(prim);402403if (result.action == SW_NOT_READY)404swTransform.BuildDrawingParams(prim, vertexCount, dec_->VertexType(), inds, RemainingIndices(inds), numDecodedVerts_, VERTEX_BUFFER_MAX, &result);405if (result.setSafeSize)406framebufferManager_->SetSafeSize(result.safeWidth, result.safeHeight);407408ApplyDrawStateLate(result.setStencil, result.stencilValue);409410LinkedShader *linked = shaderManager_->ApplyFragmentShader(vsid, vshader, pipelineState_, framebufferManager_->UseBufferedRendering());411if (!linked) {412// Not much we can do here. Let's skip drawing.413goto bail;414}415416if (result.action == SW_DRAW_INDEXED) {417vertexBufferOffset = (uint32_t)frameData.pushVertex->Push(result.drawBuffer, numDecodedVerts_ * sizeof(TransformedVertex), 4, &vertexBuffer);418indexBufferOffset = (uint32_t)frameData.pushIndex->Push(inds, sizeof(uint16_t) * result.drawNumTrans, 2, &indexBuffer);419render_->DrawIndexed(420softwareInputLayout_, vertexBuffer, vertexBufferOffset, indexBuffer, indexBufferOffset,421glprim[prim], result.drawNumTrans, GL_UNSIGNED_SHORT);422} else if (result.action == SW_CLEAR) {423u32 clearColor = result.color;424float clearDepth = result.depth;425426bool colorMask = gstate.isClearModeColorMask();427bool alphaMask = gstate.isClearModeAlphaMask();428bool depthMask = gstate.isClearModeDepthMask();429430GLbitfield target = 0;431// Without this, we will clear RGB when clearing stencil, which breaks games.432uint8_t rgbaMask = (colorMask ? 7 : 0) | (alphaMask ? 8 : 0);433if (colorMask || alphaMask) target |= GL_COLOR_BUFFER_BIT;434if (alphaMask) target |= GL_STENCIL_BUFFER_BIT;435if (depthMask) target |= GL_DEPTH_BUFFER_BIT;436437render_->Clear(clearColor, clearDepth, clearColor >> 24, target, rgbaMask, vpAndScissor_.scissorX, vpAndScissor_.scissorY, vpAndScissor_.scissorW, vpAndScissor_.scissorH);438framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);439440if (gstate_c.Use(GPU_USE_CLEAR_RAM_HACK) && colorMask && (alphaMask || gstate_c.framebufFormat == GE_FORMAT_565)) {441int scissorX1 = gstate.getScissorX1();442int scissorY1 = gstate.getScissorY1();443int scissorX2 = gstate.getScissorX2() + 1;444int scissorY2 = gstate.getScissorY2() + 1;445framebufferManager_->ApplyClearToMemory(scissorX1, scissorY1, scissorX2, scissorY2, clearColor);446}447gstate_c.Dirty(DIRTY_BLEND_STATE); // Make sure the color mask gets re-applied.448}449decOptions_.applySkinInDecode = g_Config.bSoftwareSkinning;450}451452bail:453ResetAfterDrawInline();454framebufferManager_->SetColorUpdated(gstate_c.skipDrawReason);455GPUDebug::NotifyDraw();456}457458// TODO: Refactor this to a single USE flag.459bool DrawEngineGLES::SupportsHWTessellation() {460bool hasTexelFetch = gl_extensions.GLES3 || (!gl_extensions.IsGLES && gl_extensions.VersionGEThan(3, 3, 0)) || gl_extensions.EXT_gpu_shader4;461return hasTexelFetch && gstate_c.UseAll(GPU_USE_VERTEX_TEXTURE_FETCH | GPU_USE_TEXTURE_FLOAT | GPU_USE_INSTANCE_RENDERING);462}463464bool DrawEngineGLES::UpdateUseHWTessellation(bool enable) const {465return enable && SupportsHWTessellation();466}467468void TessellationDataTransferGLES::SendDataToShader(const SimpleVertex *const *points, int size_u, int size_v, u32 vertType, const Spline::Weight2D &weights) {469bool hasColor = (vertType & GE_VTYPE_COL_MASK) != 0;470bool hasTexCoord = (vertType & GE_VTYPE_TC_MASK) != 0;471472int size = size_u * size_v;473float *pos = new float[size * 4];474float *tex = hasTexCoord ? new float[size * 4] : nullptr;475float *col = hasColor ? new float[size * 4] : nullptr;476int stride = 4;477478CopyControlPoints(pos, tex, col, stride, stride, stride, points, size, vertType);479// Removed the 1D texture support, it's unlikely to be relevant for performance.480// Control Points481if (prevSizeU < size_u || prevSizeV < size_v) {482prevSizeU = size_u;483prevSizeV = size_v;484if (data_tex[0])485renderManager_->DeleteTexture(data_tex[0]);486data_tex[0] = renderManager_->CreateTexture(GL_TEXTURE_2D, size_u * 3, size_v, 1, 1);487renderManager_->TextureImage(data_tex[0], 0, size_u * 3, size_v, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);488renderManager_->FinalizeTexture(data_tex[0], 0, false);489}490renderManager_->BindTexture(TEX_SLOT_SPLINE_POINTS, data_tex[0]);491// Position492renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, 0, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)pos, GLRAllocType::NEW);493// Texcoord494if (hasTexCoord)495renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)tex, GLRAllocType::NEW);496// Color497if (hasColor)498renderManager_->TextureSubImage(TEX_SLOT_SPLINE_POINTS, data_tex[0], 0, size_u * 2, 0, size_u, size_v, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)col, GLRAllocType::NEW);499500// Weight U501if (prevSizeWU < weights.size_u) {502prevSizeWU = weights.size_u;503if (data_tex[1])504renderManager_->DeleteTexture(data_tex[1]);505data_tex[1] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_u * 2, 1, 1, 1);506renderManager_->TextureImage(data_tex[1], 0, weights.size_u * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);507renderManager_->FinalizeTexture(data_tex[1], 0, false);508}509renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1]);510renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_U, data_tex[1], 0, 0, 0, weights.size_u * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.u, GLRAllocType::NONE);511512// Weight V513if (prevSizeWV < weights.size_v) {514prevSizeWV = weights.size_v;515if (data_tex[2])516renderManager_->DeleteTexture(data_tex[2]);517data_tex[2] = renderManager_->CreateTexture(GL_TEXTURE_2D, weights.size_v * 2, 1, 1, 1);518renderManager_->TextureImage(data_tex[2], 0, weights.size_v * 2, 1, 1, Draw::DataFormat::R32G32B32A32_FLOAT, nullptr, GLRAllocType::NONE, false);519renderManager_->FinalizeTexture(data_tex[2], 0, false);520}521renderManager_->BindTexture(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2]);522renderManager_->TextureSubImage(TEX_SLOT_SPLINE_WEIGHTS_V, data_tex[2], 0, 0, 0, weights.size_v * 2, 1, Draw::DataFormat::R32G32B32A32_FLOAT, (u8 *)weights.v, GLRAllocType::NONE);523}524525void TessellationDataTransferGLES::EndFrame() {526for (int i = 0; i < 3; i++) {527if (data_tex[i]) {528renderManager_->DeleteTexture(data_tex[i]);529data_tex[i] = nullptr;530}531}532prevSizeU = prevSizeV = prevSizeWU = prevSizeWV = 0;533}534535536