gl::Error FramebufferGL::readPixelsRowByRowWorkaround(const gl::Rectangle &area, GLenum format, GLenum type, const gl::PixelPackState &pack, GLvoid *pixels) const { intptr_t offset = reinterpret_cast<intptr_t>(pixels); const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(gl::GetSizedInternalFormat(format, type)); GLuint rowBytes = 0; ANGLE_TRY_RESULT(glFormat.computeRowPitch(type, area.width, pack.alignment, pack.rowLength), rowBytes); GLuint skipBytes = 0; ANGLE_TRY_RESULT(glFormat.computeSkipBytes(rowBytes, 0, pack, false), skipBytes); gl::PixelPackState directPack; directPack.pixelBuffer = pack.pixelBuffer; directPack.alignment = 1; mStateManager->setPixelPackState(directPack); directPack.pixelBuffer.set(nullptr); offset += skipBytes; for (GLint row = 0; row < area.height; ++row) { mFunctions->readPixels(area.x, row + area.y, area.width, 1, format, type, reinterpret_cast<GLvoid *>(offset)); offset += row * rowBytes; } return gl::NoError(); }
gl::Error FramebufferGL::readPixelsPaddingWorkaround(const gl::Rectangle &area, GLenum format, GLenum type, const gl::PixelPackState &pack, GLvoid *pixels) const { const gl::InternalFormat &glFormat = gl::GetInternalFormatInfo(gl::GetSizedInternalFormat(format, type)); GLuint rowBytes = 0; ANGLE_TRY_RESULT(glFormat.computeRowPitch(type, area.width, pack.alignment, pack.rowLength), rowBytes); GLuint skipBytes = 0; ANGLE_TRY_RESULT(glFormat.computeSkipBytes(rowBytes, 0, pack, false), skipBytes); // Get all by the last row if (area.height > 1) { mFunctions->readPixels(area.x, area.y, area.width, area.height - 1, format, type, pixels); } // Get the last row manually gl::PixelPackState directPack; directPack.pixelBuffer = pack.pixelBuffer; directPack.alignment = 1; mStateManager->setPixelPackState(directPack); directPack.pixelBuffer.set(nullptr); intptr_t lastRowOffset = reinterpret_cast<intptr_t>(pixels) + skipBytes + (area.height - 1) * rowBytes; mFunctions->readPixels(area.x, area.y + area.height - 1, area.width, 1, format, type, reinterpret_cast<GLvoid *>(lastRowOffset)); return gl::NoError(); }
gl::Error FramebufferD3D::readPixels(const gl::Context *context, const gl::Rectangle &origArea, GLenum format, GLenum type, void *pixels) { // Clip read area to framebuffer. const gl::Extents fbSize = getState().getReadAttachment()->getSize(); const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height); gl::Rectangle area; if (!ClipRectangle(origArea, fbRect, &area)) { // nothing to read return gl::NoError(); } const gl::PixelPackState &packState = context->getGLState().getPackState(); const gl::InternalFormat &sizedFormatInfo = gl::GetInternalFormatInfo(format, type); GLuint outputPitch = 0; ANGLE_TRY_RESULT(sizedFormatInfo.computeRowPitch(type, origArea.width, packState.alignment, packState.rowLength), outputPitch); GLuint outputSkipBytes = 0; ANGLE_TRY_RESULT(sizedFormatInfo.computeSkipBytes(outputPitch, 0, packState, false), outputSkipBytes); outputSkipBytes += (area.x - origArea.x) * sizedFormatInfo.pixelBytes + (area.y - origArea.y) * outputPitch; return readPixelsImpl(context, area, format, type, outputPitch, packState, reinterpret_cast<uint8_t *>(pixels) + outputSkipBytes); }
// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as // format/type at input // into the target pixel rectangle. gl::Error Image11::loadData(const gl::Context *context, const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input, bool applySkipImages) { const gl::InternalFormat &formatInfo = gl::GetSizedInternalFormatInfo(mInternalFormat); GLuint inputRowPitch = 0; ANGLE_TRY_RESULT( formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), inputRowPitch); GLuint inputDepthPitch = 0; ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(area.height, unpack.imageHeight, inputRowPitch), inputDepthPitch); GLuint inputSkipBytes = 0; ANGLE_TRY_RESULT( formatInfo.computeSkipBytes(inputRowPitch, inputDepthPitch, unpack, applySkipImages), inputSkipBytes); const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; const d3d11::Format &d3dFormatInfo = d3d11::Format::Get(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); LoadImageFunction loadFunction = d3dFormatInfo.getLoadFunctions()(type).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; ANGLE_TRY(map(context, D3D11_MAP_WRITE, &mappedImage)); uint8_t *offsetMappedData = (reinterpret_cast<uint8_t *>(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); loadFunction(area.width, area.height, area.depth, reinterpret_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); return gl::NoError(); }
gl::Error Image11::loadCompressedData(const gl::Box &area, const void *input) { const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); GLsizei inputRowPitch = 0; ANGLE_TRY_RESULT(formatInfo.computeRowPitch(GL_UNSIGNED_BYTE, area.width, 1, 0), inputRowPitch); GLsizei inputDepthPitch = 0; ANGLE_TRY_RESULT( formatInfo.computeDepthPitch(GL_UNSIGNED_BYTE, area.width, area.height, 1, 0, 0), inputDepthPitch); const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; GLuint outputBlockWidth = dxgiFormatInfo.blockWidth; GLuint outputBlockHeight = dxgiFormatInfo.blockHeight; ASSERT(area.x % outputBlockWidth == 0); ASSERT(area.y % outputBlockHeight == 0); const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(GL_UNSIGNED_BYTE).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); if (error.isError()) { return error; } uint8_t* offsetMappedData = reinterpret_cast<uint8_t*>(mappedImage.pData) + ((area.y / outputBlockHeight) * mappedImage.RowPitch + (area.x / outputBlockWidth) * outputPixelSize + area.z * mappedImage.DepthPitch); loadFunction(area.width, area.height, area.depth, reinterpret_cast<const uint8_t*>(input), inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); return gl::Error(GL_NO_ERROR); }
gl::LinkResult ProgramVk::link(const gl::Context *glContext, const gl::ProgramLinkedResources &resources, gl::InfoLog &infoLog) { ContextVk *contextVk = vk::GetImpl(glContext); RendererVk *renderer = contextVk->getRenderer(); GlslangWrapper *glslangWrapper = renderer->getGlslangWrapper(); VkDevice device = renderer->getDevice(); reset(device); std::vector<uint32_t> vertexCode; std::vector<uint32_t> fragmentCode; bool linkSuccess = false; ANGLE_TRY_RESULT( glslangWrapper->linkProgram(glContext, mState, resources, &vertexCode, &fragmentCode), linkSuccess); if (!linkSuccess) { return false; } { VkShaderModuleCreateInfo vertexShaderInfo; vertexShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; vertexShaderInfo.pNext = nullptr; vertexShaderInfo.flags = 0; vertexShaderInfo.codeSize = vertexCode.size() * sizeof(uint32_t); vertexShaderInfo.pCode = vertexCode.data(); ANGLE_TRY(mLinkedVertexModule.init(device, vertexShaderInfo)); } { VkShaderModuleCreateInfo fragmentShaderInfo; fragmentShaderInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; fragmentShaderInfo.pNext = nullptr; fragmentShaderInfo.flags = 0; fragmentShaderInfo.codeSize = fragmentCode.size() * sizeof(uint32_t); fragmentShaderInfo.pCode = fragmentCode.data(); ANGLE_TRY(mLinkedFragmentModule.init(device, fragmentShaderInfo)); } ANGLE_TRY(initPipelineLayout(contextVk)); ANGLE_TRY(initDescriptorSets(contextVk)); ANGLE_TRY(initDefaultUniformBlocks(glContext)); return true; }
// Store the pixel rectangle designated by xoffset,yoffset,width,height with pixels stored as format/type at input // into the target pixel rectangle. gl::Error Image11::loadData(const gl::Box &area, const gl::PixelUnpackState &unpack, GLenum type, const void *input) { const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(mInternalFormat); GLsizei inputRowPitch = 0; ANGLE_TRY_RESULT( formatInfo.computeRowPitch(type, area.width, unpack.alignment, unpack.rowLength), inputRowPitch); GLsizei inputDepthPitch = 0; ANGLE_TRY_RESULT(formatInfo.computeDepthPitch(type, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight), inputDepthPitch); GLsizei inputSkipBytes = formatInfo.computeSkipPixels( inputRowPitch, inputDepthPitch, unpack.skipImages, unpack.skipRows, unpack.skipPixels); const d3d11::DXGIFormatSize &dxgiFormatInfo = d3d11::GetDXGIFormatSizeInfo(mDXGIFormat); GLuint outputPixelSize = dxgiFormatInfo.pixelBytes; const d3d11::TextureFormat &d3dFormatInfo = d3d11::GetTextureFormatInfo(mInternalFormat, mRenderer->getRenderer11DeviceCaps()); LoadImageFunction loadFunction = d3dFormatInfo.loadFunctions.at(type).loadFunction; D3D11_MAPPED_SUBRESOURCE mappedImage; gl::Error error = map(D3D11_MAP_WRITE, &mappedImage); if (error.isError()) { return error; } uint8_t *offsetMappedData = (reinterpret_cast<uint8_t*>(mappedImage.pData) + (area.y * mappedImage.RowPitch + area.x * outputPixelSize + area.z * mappedImage.DepthPitch)); loadFunction(area.width, area.height, area.depth, reinterpret_cast<const uint8_t *>(input) + inputSkipBytes, inputRowPitch, inputDepthPitch, offsetMappedData, mappedImage.RowPitch, mappedImage.DepthPitch); unmap(); return gl::Error(GL_NO_ERROR); }
gl::ErrorOrResult<const std::vector<ID3D11Buffer *> *> TransformFeedback11::getSOBuffers( const gl::Context *context) { for (size_t bindingIdx = 0; bindingIdx < mBuffers.size(); bindingIdx++) { const auto &binding = mState.getIndexedBuffer(bindingIdx); if (binding.get() != nullptr) { Buffer11 *storage = GetImplAs<Buffer11>(binding.get()); ANGLE_TRY_RESULT(storage->getBuffer(context, BUFFER_USAGE_VERTEX_OR_TRANSFORM_FEEDBACK), mBuffers[bindingIdx]); } } return &mBuffers; }
Error FramebufferGL::readPixels(ContextImpl *context, const gl::Rectangle &area, GLenum format, GLenum type, GLvoid *pixels) const { // TODO: don't sync the pixel pack state here once the dirty bits contain the pixel pack buffer // binding const PixelPackState &packState = context->getGLState().getPackState(); mStateManager->setPixelPackState(packState); nativegl::ReadPixelsFormat readPixelsFormat = nativegl::GetReadPixelsFormat(mFunctions, mWorkarounds, format, type); GLenum readFormat = readPixelsFormat.format; GLenum readType = readPixelsFormat.type; mStateManager->bindFramebuffer(GL_READ_FRAMEBUFFER, mFramebufferID); if (mWorkarounds.packOverlappingRowsSeparatelyPackBuffer && packState.pixelBuffer.get() && packState.rowLength != 0 && packState.rowLength < area.width) { return readPixelsRowByRowWorkaround(area, readFormat, readType, packState, pixels); } if (mWorkarounds.packLastRowSeparatelyForPaddingInclusion) { gl::Extents size(area.width, area.height, 1); bool apply; ANGLE_TRY_RESULT(ShouldApplyLastRowPaddingWorkaround(size, packState, readFormat, readType, false, pixels), apply); if (apply) { return readPixelsPaddingWorkaround(area, readFormat, readType, packState, pixels); } } mFunctions->readPixels(area.x, area.y, area.width, area.height, readFormat, readType, pixels); return gl::NoError(); }
gl::Error PixelTransfer11::copyBufferToTexture(const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { ANGLE_TRY(loadResources()); gl::Extents destSize = destRenderTarget->getExtents(); ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); const gl::Buffer &sourceBuffer = *unpack.pixelBuffer.get(); ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); ID3D11PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); ASSERT(pixelShader); // The SRV must be in the proper read format, which may be different from the destination format // EG: for half float data, we can load full precision floats with implicit conversion GLenum unsizedFormat = gl::GetInternalFormatInfo(destinationFormat).format; GLenum sourceFormat = gl::GetSizedInternalFormat(unsizedFormat, sourcePixelsType); const d3d11::Format &sourceFormatInfo = d3d11::Format::Get(sourceFormat, mRenderer->getRenderer11DeviceCaps()); DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); Buffer11 *bufferStorage11 = GetAs<Buffer11>(sourceBuffer.getImplementation()); ID3D11ShaderResourceView *bufferSRV = nullptr; ANGLE_TRY_RESULT(bufferStorage11->getSRV(srvFormat), bufferSRV); ASSERT(bufferSRV != nullptr); ID3D11RenderTargetView *textureRTV = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(textureRTV != nullptr); CopyShaderParams shaderParams; setBufferToTextureCopyParams(destArea, destSize, sourceFormat, unpack, offset, &shaderParams); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); ID3D11Buffer *nullBuffer = nullptr; UINT zero = 0; // Are we doing a 2D or 3D copy? ID3D11GeometryShader *geometryShader = ((destSize.depth > 1) ? mBufferToTextureGS : NULL); auto stateManager = mRenderer->getStateManager(); deviceContext->VSSetShader(mBufferToTextureVS, NULL, 0); deviceContext->GSSetShader(geometryShader, NULL, 0); deviceContext->PSSetShader(pixelShader, NULL, 0); stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, bufferSRV); deviceContext->IASetInputLayout(NULL); deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); deviceContext->IASetVertexBuffers(0, 1, &nullBuffer, &zero, &zero); deviceContext->OMSetBlendState(NULL, NULL, 0xFFFFFFF); deviceContext->OMSetDepthStencilState(mCopyDepthStencilState, 0xFFFFFFFF); deviceContext->RSSetState(mCopyRasterizerState); stateManager->setOneTimeRenderTarget(textureRTV, nullptr); if (!StructEquals(mParamsData, shaderParams)) { d3d11::SetBufferData(deviceContext, mParamsConstantBuffer, shaderParams); mParamsData = shaderParams; } deviceContext->VSSetConstantBuffers(0, 1, &mParamsConstantBuffer); // Set the viewport D3D11_VIEWPORT viewport; viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.Width = static_cast<FLOAT>(destSize.width); viewport.Height = static_cast<FLOAT>(destSize.height); viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; deviceContext->RSSetViewports(1, &viewport); UINT numPixels = (destArea.width * destArea.height * destArea.depth); deviceContext->Draw(numPixels, 0); // Unbind textures and render targets and vertex buffer stateManager->setShaderResource(gl::SAMPLER_PIXEL, 0, NULL); deviceContext->VSSetConstantBuffers(0, 1, &nullBuffer); mRenderer->markAllStateDirty(); return gl::NoError(); }
gl::Error PixelTransfer11::copyBufferToTexture(const gl::Context *context, const gl::PixelUnpackState &unpack, unsigned int offset, RenderTargetD3D *destRenderTarget, GLenum destinationFormat, GLenum sourcePixelsType, const gl::Box &destArea) { ANGLE_TRY(loadResources()); gl::Extents destSize = destRenderTarget->getExtents(); ASSERT(destArea.x >= 0 && destArea.x + destArea.width <= destSize.width && destArea.y >= 0 && destArea.y + destArea.height <= destSize.height && destArea.z >= 0 && destArea.z + destArea.depth <= destSize.depth ); const gl::Buffer &sourceBuffer = *context->getGLState().getTargetBuffer(gl::BufferBinding::PixelUnpack); ASSERT(mRenderer->supportsFastCopyBufferToTexture(destinationFormat)); const d3d11::PixelShader *pixelShader = findBufferToTexturePS(destinationFormat); ASSERT(pixelShader); // The SRV must be in the proper read format, which may be different from the destination format // EG: for half float data, we can load full precision floats with implicit conversion GLenum unsizedFormat = gl::GetUnsizedFormat(destinationFormat); const gl::InternalFormat &sourceglFormatInfo = gl::GetInternalFormatInfo(unsizedFormat, sourcePixelsType); const d3d11::Format &sourceFormatInfo = d3d11::Format::Get( sourceglFormatInfo.sizedInternalFormat, mRenderer->getRenderer11DeviceCaps()); DXGI_FORMAT srvFormat = sourceFormatInfo.srvFormat; ASSERT(srvFormat != DXGI_FORMAT_UNKNOWN); Buffer11 *bufferStorage11 = GetAs<Buffer11>(sourceBuffer.getImplementation()); const d3d11::ShaderResourceView *bufferSRV = nullptr; ANGLE_TRY_RESULT(bufferStorage11->getSRV(context, srvFormat), bufferSRV); ASSERT(bufferSRV != nullptr); const d3d11::RenderTargetView &textureRTV = GetAs<RenderTarget11>(destRenderTarget)->getRenderTargetView(); ASSERT(textureRTV.valid()); CopyShaderParams shaderParams; setBufferToTextureCopyParams(destArea, destSize, sourceglFormatInfo.sizedInternalFormat, unpack, offset, &shaderParams); ID3D11DeviceContext *deviceContext = mRenderer->getDeviceContext(); // Are we doing a 2D or 3D copy? const auto *geometryShader = ((destSize.depth > 1) ? &mBufferToTextureGS : nullptr); StateManager11 *stateManager = mRenderer->getStateManager(); stateManager->setDrawShaders(&mBufferToTextureVS, geometryShader, pixelShader); stateManager->setShaderResource(gl::SHADER_FRAGMENT, 0, bufferSRV); stateManager->setInputLayout(nullptr); stateManager->setPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); stateManager->setSingleVertexBuffer(nullptr, 0, 0); stateManager->setSimpleBlendState(nullptr); stateManager->setDepthStencilState(&mCopyDepthStencilState, 0xFFFFFFFF); stateManager->setRasterizerState(&mCopyRasterizerState); stateManager->setRenderTarget(textureRTV.get(), nullptr); if (!StructEquals(mParamsData, shaderParams)) { d3d11::SetBufferData(deviceContext, mParamsConstantBuffer.get(), shaderParams); mParamsData = shaderParams; } stateManager->setVertexConstantBuffer(0, &mParamsConstantBuffer); // Set the viewport stateManager->setSimpleViewport(destSize); UINT numPixels = (destArea.width * destArea.height * destArea.depth); deviceContext->Draw(numPixels, 0); return gl::NoError(); }
gl::Error TextureGL::setStorage(GLenum target, size_t levels, GLenum internalFormat, const gl::Extents &size) { // TODO: emulate texture storage with TexImage calls if on GL version <4.2 or the // ARB_texture_storage extension is not available. nativegl::TexStorageFormat texStorageFormat = nativegl::GetTexStorageFormat(mFunctions, mWorkarounds, internalFormat); mStateManager->bindTexture(mState.mTarget, mTextureID); if (UseTexImage2D(mState.mTarget)) { ASSERT(size.depth == 1); if (mFunctions->texStorage2D) { mFunctions->texStorage2D(target, static_cast<GLsizei>(levels), texStorageFormat.internalFormat, size.width, size.height); } else { // Make sure no pixel unpack buffer is bound mStateManager->bindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); const gl::InternalFormat &internalFormatInfo = gl::GetInternalFormatInfo(internalFormat); // Internal format must be sized ASSERT(internalFormatInfo.pixelBytes != 0); for (size_t level = 0; level < levels; level++) { gl::Extents levelSize(std::max(size.width >> level, 1), std::max(size.height >> level, 1), 1); if (mState.mTarget == GL_TEXTURE_2D) { if (internalFormatInfo.compressed) { GLuint dataSize = 0; ANGLE_TRY_RESULT(internalFormatInfo.computeCompressedImageSize( GL_UNSIGNED_BYTE, levelSize), dataSize); mFunctions->compressedTexImage2D(target, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr); } else { mFunctions->texImage2D(target, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, internalFormatInfo.format, internalFormatInfo.type, nullptr); } } else if (mState.mTarget == GL_TEXTURE_CUBE_MAP) { for (GLenum face = gl::FirstCubeMapTextureTarget; face <= gl::LastCubeMapTextureTarget; face++) { if (internalFormatInfo.compressed) { GLuint dataSize = 0; ANGLE_TRY_RESULT(internalFormatInfo.computeCompressedImageSize( GL_UNSIGNED_BYTE, levelSize), dataSize); mFunctions->compressedTexImage2D( face, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, static_cast<GLsizei>(dataSize), nullptr); } else { mFunctions->texImage2D(face, static_cast<GLint>(level), texStorageFormat.internalFormat, levelSize.width, levelSize.height, 0, internalFormatInfo.format, internalFormatInfo.type, nullptr); } } } else { UNREACHABLE(); } } } }
gl::Error TextureGL::setSubImageRowByRowWorkaround(GLenum target, size_t level, const gl::Box &area, GLenum format, GLenum type, const gl::PixelUnpackState &unpack, const uint8_t *pixels) { gl::PixelUnpackState unpackToUse; unpackToUse.pixelBuffer = unpack.pixelBuffer; mStateManager->setPixelUnpackState(unpackToUse); unpackToUse.pixelBuffer.set(nullptr); GLenum sizedFormat = gl::GetSizedInternalFormat(mState.getImageDesc(mState.mTarget, level).internalFormat, type); const gl::InternalFormat &formatInfo = gl::GetInternalFormatInfo(sizedFormat); GLuint rowBytes = 0; ANGLE_TRY_RESULT( formatInfo.computeRowPitch(GL_NONE, area.width, unpack.alignment, unpack.rowLength), rowBytes); GLuint imageBytes = 0; ANGLE_TRY_RESULT( formatInfo.computeDepthPitch(GL_NONE, area.width, area.height, unpack.alignment, unpack.rowLength, unpack.imageHeight), imageBytes); bool useTexImage3D = UseTexImage3D(mState.mTarget); GLuint skipBytes = 0; ANGLE_TRY_RESULT(formatInfo.computeSkipBytes(rowBytes, imageBytes, unpack.skipImages, unpack.skipRows, unpack.skipPixels, useTexImage3D), skipBytes); const uint8_t *pixelsWithSkip = pixels + skipBytes; if (useTexImage3D) { for (GLint image = 0; image < area.depth; ++image) { GLint imageByteOffset = image * imageBytes; for (GLint row = 0; row < area.height; ++row) { GLint byteOffset = imageByteOffset + row * rowBytes; const GLubyte *rowPixels = pixelsWithSkip + byteOffset; mFunctions->texSubImage3D(target, static_cast<GLint>(level), area.x, row + area.y, image + area.z, area.width, 1, 1, format, type, rowPixels); } } } else if (UseTexImage2D(mState.mTarget)) { for (GLint row = 0; row < area.height; ++row) { GLint byteOffset = row * rowBytes; const GLubyte *rowPixels = pixelsWithSkip + byteOffset; mFunctions->texSubImage2D(target, static_cast<GLint>(level), area.x, row + area.y, area.width, 1, format, type, rowPixels); } } else { UNREACHABLE(); } return gl::NoError(); }
gl::Error VertexDeclarationCache::applyDeclaration( IDirect3DDevice9 *device, const std::vector<TranslatedAttribute> &attributes, gl::Program *program, GLint start, GLsizei instances, GLsizei *repeatDraw) { ASSERT(gl::MAX_VERTEX_ATTRIBS >= attributes.size()); *repeatDraw = 1; const size_t invalidAttribIndex = attributes.size(); size_t indexedAttribute = invalidAttribIndex; size_t instancedAttribute = invalidAttribIndex; if (instances == 0) { for (size_t i = 0; i < attributes.size(); ++i) { if (attributes[i].divisor != 0) { // If a divisor is set, it still applies even if an instanced draw was not used, so treat // as a single-instance draw. instances = 1; break; } } } if (instances > 0) { // Find an indexed attribute to be mapped to D3D stream 0 for (size_t i = 0; i < attributes.size(); i++) { if (attributes[i].active) { if (indexedAttribute == invalidAttribIndex && attributes[i].divisor == 0) { indexedAttribute = i; } else if (instancedAttribute == invalidAttribIndex && attributes[i].divisor != 0) { instancedAttribute = i; } if (indexedAttribute != invalidAttribIndex && instancedAttribute != invalidAttribIndex) break; // Found both an indexed and instanced attribute } } // The validation layer checks that there is at least one active attribute with a zero divisor as per // the GL_ANGLE_instanced_arrays spec. ASSERT(indexedAttribute != invalidAttribIndex); } D3DCAPS9 caps; device->GetDeviceCaps(&caps); D3DVERTEXELEMENT9 elements[gl::MAX_VERTEX_ATTRIBS + 1]; D3DVERTEXELEMENT9 *element = &elements[0]; ProgramD3D *programD3D = GetImplAs<ProgramD3D>(program); const auto &semanticIndexes = programD3D->getAttribLocationToD3DSemantics(); for (size_t i = 0; i < attributes.size(); i++) { if (attributes[i].active) { // Directly binding the storage buffer is not supported for d3d9 ASSERT(attributes[i].storage == nullptr); int stream = static_cast<int>(i); if (instances > 0) { // Due to a bug on ATI cards we can't enable instancing when none of the attributes are instanced. if (instancedAttribute == invalidAttribIndex) { *repeatDraw = instances; } else { if (i == indexedAttribute) { stream = 0; } else if (i == 0) { stream = static_cast<int>(indexedAttribute); } UINT frequency = 1; if (attributes[i].divisor == 0) { frequency = D3DSTREAMSOURCE_INDEXEDDATA | instances; } else { frequency = D3DSTREAMSOURCE_INSTANCEDATA | attributes[i].divisor; } device->SetStreamSourceFreq(stream, frequency); mInstancingEnabled = true; } } VertexBuffer9 *vertexBuffer = GetAs<VertexBuffer9>(attributes[i].vertexBuffer.get()); unsigned int offset = 0; ANGLE_TRY_RESULT(attributes[i].computeOffset(start), offset); if (mAppliedVBs[stream].serial != attributes[i].serial || mAppliedVBs[stream].stride != attributes[i].stride || mAppliedVBs[stream].offset != offset) { device->SetStreamSource(stream, vertexBuffer->getBuffer(), offset, attributes[i].stride); mAppliedVBs[stream].serial = attributes[i].serial; mAppliedVBs[stream].stride = attributes[i].stride; mAppliedVBs[stream].offset = offset; } gl::VertexFormatType vertexformatType = gl::GetVertexFormatType(*attributes[i].attribute, GL_FLOAT); const d3d9::VertexFormat &d3d9VertexInfo = d3d9::GetVertexFormatInfo(caps.DeclTypes, vertexformatType); element->Stream = static_cast<WORD>(stream); element->Offset = 0; element->Type = static_cast<BYTE>(d3d9VertexInfo.nativeFormat); element->Method = D3DDECLMETHOD_DEFAULT; element->Usage = D3DDECLUSAGE_TEXCOORD; element->UsageIndex = static_cast<BYTE>(semanticIndexes[i]); element++; } } if (instances == 0 || instancedAttribute == invalidAttribIndex) { if (mInstancingEnabled) { for (int i = 0; i < gl::MAX_VERTEX_ATTRIBS; i++) { device->SetStreamSourceFreq(i, 1); } mInstancingEnabled = false; } } static const D3DVERTEXELEMENT9 end = D3DDECL_END(); *(element++) = end; for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) { VertexDeclCacheEntry *entry = &mVertexDeclCache[i]; if (memcmp(entry->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)) == 0 && entry->vertexDeclaration) { entry->lruCount = ++mMaxLru; if(entry->vertexDeclaration != mLastSetVDecl) { device->SetVertexDeclaration(entry->vertexDeclaration); mLastSetVDecl = entry->vertexDeclaration; } return gl::NoError(); } } VertexDeclCacheEntry *lastCache = mVertexDeclCache; for (int i = 0; i < NUM_VERTEX_DECL_CACHE_ENTRIES; i++) { if (mVertexDeclCache[i].lruCount < lastCache->lruCount) { lastCache = &mVertexDeclCache[i]; } } if (lastCache->vertexDeclaration != nullptr) { SafeRelease(lastCache->vertexDeclaration); // mLastSetVDecl is set to the replacement, so we don't have to worry // about it. } memcpy(lastCache->cachedElements, elements, (element - elements) * sizeof(D3DVERTEXELEMENT9)); HRESULT result = device->CreateVertexDeclaration(elements, &lastCache->vertexDeclaration); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to create internal vertex declaration, result: 0x%X.", result); } device->SetVertexDeclaration(lastCache->vertexDeclaration); mLastSetVDecl = lastCache->vertexDeclaration; lastCache->lruCount = ++mMaxLru; return gl::NoError(); }