blob: 237bde37e52a1ee5bb84c6beda509334a8b1ef30 [file] [log] [blame]
//
// 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.
//
// RendererD3D.cpp: Implementation of the base D3D Renderer.
#include "libANGLE/renderer/d3d/RendererD3D.h"
#include "common/MemoryBuffer.h"
#include "common/debug.h"
#include "common/utilities.h"
#include "libANGLE/Context.h"
#include "libANGLE/Display.h"
#include "libANGLE/Framebuffer.h"
#include "libANGLE/FramebufferAttachment.h"
#include "libANGLE/ImageIndex.h"
#include "libANGLE/ResourceManager.h"
#include "libANGLE/State.h"
#include "libANGLE/VertexArray.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/ContextImpl.h"
#include "libANGLE/renderer/TextureImpl.h"
#include "libANGLE/renderer/d3d/BufferD3D.h"
#include "libANGLE/renderer/d3d/DeviceD3D.h"
#include "libANGLE/renderer/d3d/DisplayD3D.h"
#include "libANGLE/renderer/d3d/IndexDataManager.h"
#include "libANGLE/renderer/d3d/ProgramD3D.h"
#include "libANGLE/renderer/d3d/SamplerD3D.h"
#include "libANGLE/renderer/d3d/TextureD3D.h"
namespace rx
{
RendererD3D::RendererD3D(egl::Display *display)
: mDisplay(display),
mPresentPathFastEnabled(false),
mCapsInitialized(false),
mFeaturesInitialized(false),
mDisjoint(false),
mDeviceLost(false)
{}
RendererD3D::~RendererD3D() {}
bool RendererD3D::skipDraw(const gl::State &glState, gl::PrimitiveMode drawMode)
{
if (drawMode == gl::PrimitiveMode::Points)
{
bool usesPointSize = GetImplAs<ProgramD3D>(glState.getProgram())->usesPointSize();
// ProgramBinary assumes non-point rendering if gl_PointSize isn't written,
// which affects varying interpolation. Since the value of gl_PointSize is
// undefined when not written, just skip drawing to avoid unexpected results.
if (!usesPointSize && !glState.isTransformFeedbackActiveUnpaused())
{
// Notify developers of risking undefined behavior.
WARN() << "Point rendering without writing to gl_PointSize.";
return true;
}
}
else if (gl::IsTriangleMode(drawMode))
{
if (glState.getRasterizerState().cullFace &&
glState.getRasterizerState().cullMode == gl::CullFaceMode::FrontAndBack)
{
return true;
}
}
return false;
}
gl::GraphicsResetStatus RendererD3D::getResetStatus()
{
if (!mDeviceLost)
{
if (testDeviceLost())
{
mDeviceLost = true;
notifyDeviceLost();
return gl::GraphicsResetStatus::UnknownContextReset;
}
return gl::GraphicsResetStatus::NoError;
}
if (testDeviceResettable())
{
return gl::GraphicsResetStatus::NoError;
}
return gl::GraphicsResetStatus::UnknownContextReset;
}
void RendererD3D::notifyDeviceLost()
{
mDisplay->notifyDeviceLost();
}
std::string RendererD3D::getVendorString() const
{
LUID adapterLuid = {};
if (getLUID(&adapterLuid))
{
char adapterLuidString[64];
sprintf_s(adapterLuidString, sizeof(adapterLuidString), "(adapter LUID: %08x%08x)",
adapterLuid.HighPart, adapterLuid.LowPart);
return std::string(adapterLuidString);
}
return std::string("");
}
void RendererD3D::setGPUDisjoint()
{
mDisjoint = true;
}
GLint RendererD3D::getGPUDisjoint()
{
bool disjoint = mDisjoint;
// Disjoint flag is cleared when read
mDisjoint = false;
return disjoint;
}
GLint64 RendererD3D::getTimestamp()
{
// D3D has no way to get an actual timestamp reliably so 0 is returned
return 0;
}
void RendererD3D::ensureCapsInitialized() const
{
if (!mCapsInitialized)
{
generateCaps(&mNativeCaps, &mNativeTextureCaps, &mNativeExtensions, &mNativeLimitations);
mCapsInitialized = true;
}
}
const gl::Caps &RendererD3D::getNativeCaps() const
{
ensureCapsInitialized();
return mNativeCaps;
}
const gl::TextureCapsMap &RendererD3D::getNativeTextureCaps() const
{
ensureCapsInitialized();
return mNativeTextureCaps;
}
const gl::Extensions &RendererD3D::getNativeExtensions() const
{
ensureCapsInitialized();
return mNativeExtensions;
}
const gl::Limitations &RendererD3D::getNativeLimitations() const
{
ensureCapsInitialized();
return mNativeLimitations;
}
Serial RendererD3D::generateSerial()
{
return mSerialFactory.generate();
}
bool InstancedPointSpritesActive(ProgramD3D *programD3D, gl::PrimitiveMode mode)
{
return programD3D->usesPointSize() && programD3D->usesInstancedPointSpriteEmulation() &&
mode == gl::PrimitiveMode::Points;
}
angle::Result RendererD3D::initRenderTarget(const gl::Context *context,
RenderTargetD3D *renderTarget)
{
return clearRenderTarget(context, renderTarget, gl::ColorF(0, 0, 0, 0), 1, 0);
}
const angle::FeaturesD3D &RendererD3D::getFeatures() const
{
if (!mFeaturesInitialized)
{
initializeFeatures(&mFeatures);
mFeaturesInitialized = true;
}
return mFeatures;
}
unsigned int GetBlendSampleMask(const gl::State &glState, int samples)
{
unsigned int mask = 0;
if (glState.isSampleCoverageEnabled())
{
GLfloat coverageValue = glState.getSampleCoverageValue();
if (coverageValue != 0)
{
float threshold = 0.5f;
for (int i = 0; i < samples; ++i)
{
mask <<= 1;
if ((i + 1) * coverageValue >= threshold)
{
threshold += 1.0f;
mask |= 1;
}
}
}
bool coverageInvert = glState.getSampleCoverageInvert();
if (coverageInvert)
{
mask = ~mask;
}
}
else
{
mask = 0xFFFFFFFF;
}
if (glState.isSampleMaskEnabled())
{
mask &= glState.getSampleMaskWord(0);
}
return mask;
}
GLenum DefaultGLErrorCode(HRESULT hr)
{
switch (hr)
{
#ifdef ANGLE_ENABLE_D3D9
case D3DERR_OUTOFVIDEOMEMORY:
#endif
case E_OUTOFMEMORY:
return GL_OUT_OF_MEMORY;
default:
return GL_INVALID_OPERATION;
}
}
} // namespace rx