BufferStorage11::TypedBufferStorage11 *BufferStorage11::getStorage(BufferUsage usage) { TypedBufferStorage11 *directBuffer = NULL; auto directBufferIt = mTypedBuffers.find(usage); if (directBufferIt != mTypedBuffers.end()) { directBuffer = directBufferIt->second; } if (!directBuffer) { if (usage == BUFFER_USAGE_PIXEL_PACK) { directBuffer = new PackStorage11(mRenderer); } else { // buffer is not allocated, create it directBuffer = new NativeBuffer11(mRenderer, usage); } mTypedBuffers.insert(std::make_pair(usage, directBuffer)); } // resize buffer if (directBuffer->getSize() < mSize) { if (!directBuffer->resize(mSize, true)) { // Out of memory error return NULL; } } TypedBufferStorage11 *latestBuffer = getLatestStorage(); if (latestBuffer && latestBuffer->getDataRevision() > directBuffer->getDataRevision()) { // if copying from a pack buffer to a non-staging native buffer, we must first // copy through the staging buffer, because other native buffers can't be mapped if (latestBuffer->getUsage() == BUFFER_USAGE_PIXEL_PACK && !directBuffer->isMappable()) { NativeBuffer11 *stagingBuffer = getStagingBuffer(); stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); directBuffer->setDataRevision(latestBuffer->getDataRevision()); latestBuffer = stagingBuffer; } // if copyFromStorage returns true, the D3D buffer has been recreated // and we should update our serial if (directBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) { updateSerial(); } directBuffer->setDataRevision(latestBuffer->getDataRevision()); } return directBuffer; }
gl::Error VertexBuffer9::initialize(unsigned int size, bool dynamicUsage) { SafeRelease(mVertexBuffer); updateSerial(); if (size > 0) { DWORD flags = D3DUSAGE_WRITEONLY; if (dynamicUsage) { flags |= D3DUSAGE_DYNAMIC; } HRESULT result = mRenderer->createVertexBuffer(size, flags, &mVertexBuffer); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); } } mBufferSize = size; mDynamicUsage = dynamicUsage; return gl::Error(GL_NO_ERROR); }
gl::Error VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) { SafeRelease(mBuffer); updateSerial(); if (size > 0) { ID3D11Device* dxDevice = mRenderer->getDevice(); D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = size; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal vertex buffer of size, %lu.", size); } } mBufferSize = size; mDynamicUsage = dynamicUsage; return gl::Error(GL_NO_ERROR); }
bool IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { SafeRelease(mBuffer); updateSerial(); if (bufferSize > 0) { ID3D11Device* dxDevice = mRenderer->getDevice(); D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = bufferSize; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return false; } } mBufferSize = bufferSize; mIndexType = indexType; mDynamicUsage = dynamic; return true; }
bool VertexBuffer11::initialize(unsigned int size, bool dynamicUsage) { if (mBuffer) { mBuffer->Release(); mBuffer = NULL; } updateSerial(); if (size > 0) { ID3D11Device* dxDevice = mRenderer->getDevice(); D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = size; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return false; } } mBufferSize = size; mDynamicUsage = dynamicUsage; return true; }
void QVGPixmapData::resize(int wid, int ht) { if (w == wid && h == ht) { updateSerial(); return; } w = wid; h = ht; d = 32; // We always use ARGB_Premultiplied for VG pixmaps. is_null = (w <= 0 || h <= 0); source = QVolatileImage(); recreate = true; updateSerial(); }
/// -------------------- Update -------------------- /// void MotionerIMU::update() { updateSerial(); updateValues(); const bool ret = updateVelocity(); // updateCAN(); }
BufferD3D::BufferD3D(BufferFactoryD3D *factory) : BufferImpl(), mFactory(factory), mStaticVertexBuffer(nullptr), mStaticIndexBuffer(nullptr), mUnmodifiedDataUse(0), mUsage(D3D_BUFFER_USAGE_STATIC) { updateSerial(); }
bool IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { if (mIndexBuffer) { mIndexBuffer->Release(); mIndexBuffer = NULL; } updateSerial(); if (bufferSize > 0) { D3DFORMAT format; if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) { format = D3DFMT_INDEX16; } else if (indexType == GL_UNSIGNED_INT) { if (mRenderer->get32BitIndexSupport()) { format = D3DFMT_INDEX32; } else { ERR("Attempted to create a 32-bit index buffer but renderer does not support 32-bit indices."); return false; } } else { ERR("Invalid index type %u.", indexType); return false; } DWORD usageFlags = D3DUSAGE_WRITEONLY; if (dynamic) { usageFlags |= D3DUSAGE_DYNAMIC; } HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); if (FAILED(result)) { ERR("Failed to create an index buffer of size %u, result: 0x%08x.", mBufferSize, result); return false; } } mBufferSize = bufferSize; mIndexType = indexType; mDynamic = dynamic; return true; }
BufferD3D::BufferD3D(BufferFactoryD3D *factory) : BufferImpl(), mFactory(factory), mStaticIndexBuffer(nullptr), mStaticBufferCacheTotalSize(0), mStaticVertexBufferOutOfDate(false), mUnmodifiedDataUse(0), mUsage(D3DBufferUsage::STATIC) { updateSerial(); }
void QVGPixmapData::fromNativeType(void* pixmap, NativeType type) { if (type == QPixmapData::SgImage && pixmap) { #if defined(QT_SYMBIAN_SUPPORTS_SGIMAGE) && !defined(QT_NO_EGL) RSgImage *sgImage = reinterpret_cast<RSgImage*>(pixmap); destroyImages(); prevSize = QSize(); vgImage = sgImageToVGImage(context, *sgImage); if (vgImage != VG_INVALID_HANDLE) { w = vgGetParameteri(vgImage, VG_IMAGE_WIDTH); h = vgGetParameteri(vgImage, VG_IMAGE_HEIGHT); d = 32; // We always use ARGB_Premultiplied for VG pixmaps. } is_null = (w <= 0 || h <= 0); source = QVolatileImage(); // readback will be done later, only when needed recreate = false; prevSize = QSize(w, h); updateSerial(); #endif } else if (type == QPixmapData::FbsBitmap && pixmap) { CFbsBitmap *bitmap = reinterpret_cast<CFbsBitmap *>(pixmap); QSize size(bitmap->SizeInPixels().iWidth, bitmap->SizeInPixels().iHeight); resize(size.width(), size.height()); source = QVolatileImage(bitmap); // duplicates only, if possible if (source.isNull()) return; if (!conversionLessFormat(source.format())) { // Here we may need to copy if the formats do not match. // (e.g. for display modes other than EColor16MAP and EColor16MU) source.beginDataAccess(); QImage::Format format = idealFormat(&source.imageRef(), Qt::AutoColor); source.endDataAccess(true); source.ensureFormat(format); } recreate = true; } else if (type == QPixmapData::VolatileImage && pixmap) { QVolatileImage *img = static_cast<QVolatileImage *>(pixmap); resize(img->width(), img->height()); source = *img; recreate = true; } else if (type == QPixmapData::NativeImageHandleProvider && pixmap) { destroyImages(); nativeImageHandleProvider = static_cast<QNativeImageHandleProvider *>(pixmap); // Cannot defer the retrieval, we need at least the size right away. createFromNativeImageHandleProvider(); } }
QVGPixmapData::QVGPixmapData(PixelType type) : QPixmapData(type, OpenVGClass) { Q_ASSERT(type == QPixmapData::PixmapType); vgImage = VG_INVALID_HANDLE; vgImageOpacity = VG_INVALID_HANDLE; cachedOpacity = 1.0f; recreate = true; inImagePool = false; inLRU = false; #if defined(Q_OS_SYMBIAN) nativeImageHandleProvider = 0; nativeImageHandle = 0; #endif #if !defined(QT_NO_EGL) context = 0; qt_vg_register_pixmap(this); #endif updateSerial(); }
gl::Error IndexBuffer11::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { SafeRelease(mBuffer); updateSerial(); if (bufferSize > 0) { ID3D11Device* dxDevice = mRenderer->getDevice(); D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = bufferSize; bufferDesc.Usage = D3D11_USAGE_DYNAMIC; bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; HRESULT result = dxDevice->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); } if (dynamic) { d3d11::SetDebugName(mBuffer, "IndexBuffer11 (dynamic)"); } else { d3d11::SetDebugName(mBuffer, "IndexBuffer11 (static)"); } } mBufferSize = bufferSize; mIndexType = indexType; mDynamicUsage = dynamic; return gl::Error(GL_NO_ERROR); }
gl::Error IndexBuffer9::initialize(unsigned int bufferSize, GLenum indexType, bool dynamic) { SafeRelease(mIndexBuffer); updateSerial(); if (bufferSize > 0) { D3DFORMAT format = D3DFMT_UNKNOWN; if (indexType == GL_UNSIGNED_SHORT || indexType == GL_UNSIGNED_BYTE) { format = D3DFMT_INDEX16; } else if (indexType == GL_UNSIGNED_INT) { ASSERT(mRenderer->getRendererExtensions().elementIndexUint); format = D3DFMT_INDEX32; } else UNREACHABLE(); DWORD usageFlags = D3DUSAGE_WRITEONLY; if (dynamic) { usageFlags |= D3DUSAGE_DYNAMIC; } HRESULT result = mRenderer->createIndexBuffer(bufferSize, usageFlags, format, &mIndexBuffer); if (FAILED(result)) { return gl::Error(GL_OUT_OF_MEMORY, "Failed to allocate internal index buffer of size, %lu.", bufferSize); } } mBufferSize = bufferSize; mIndexType = indexType; mDynamic = dynamic; return gl::Error(GL_NO_ERROR); }
void Memory::updateIrqs(unsigned long cc) { updateSerial(cc); updateTimaIrq(cc); lcd_.update(cc); }
unsigned long Memory::event(unsigned long cc) { if (lastOamDmaUpdate_ != disabled_time) updateOamDma(cc); switch (intreq_.minEventId()) { case intevent_unhalt: intreq_.unhalt(); intreq_.setEventTime<intevent_unhalt>(disabled_time); break; case intevent_end: intreq_.setEventTime<intevent_end>(disabled_time - 1); while (cc >= intreq_.minEventTime() && intreq_.eventTime(intevent_end) != disabled_time) { cc = event(cc); } intreq_.setEventTime<intevent_end>(disabled_time); break; case intevent_blit: { bool const lcden = ioamhram_[0x140] & lcdc_en; unsigned long blitTime = intreq_.eventTime(intevent_blit); if (lcden | blanklcd_) { lcd_.updateScreen(blanklcd_, cc); intreq_.setEventTime<intevent_blit>(disabled_time); intreq_.setEventTime<intevent_end>(disabled_time); while (cc >= intreq_.minEventTime()) cc = event(cc); } else blitTime += 70224 << isDoubleSpeed(); blanklcd_ = lcden ^ 1; intreq_.setEventTime<intevent_blit>(blitTime); } break; case intevent_serial: updateSerial(cc); break; case intevent_oam: intreq_.setEventTime<intevent_oam>(lastOamDmaUpdate_ == disabled_time ? static_cast<unsigned long>(disabled_time) : intreq_.eventTime(intevent_oam) + 0xA0 * 4); break; case intevent_dma: { bool const doubleSpeed = isDoubleSpeed(); unsigned dmaSrc = dmaSource_; unsigned dmaDest = dmaDestination_; unsigned dmaLength = ((ioamhram_[0x155] & 0x7F) + 0x1) * 0x10; unsigned length = hdmaReqFlagged(intreq_) ? 0x10 : dmaLength; ackDmaReq(intreq_); if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) { length = 0x10000 - dmaDest; ioamhram_[0x155] |= 0x80; } dmaLength -= length; if (!(ioamhram_[0x140] & lcdc_en)) dmaLength = 0; { unsigned long lOamDmaUpdate = lastOamDmaUpdate_; lastOamDmaUpdate_ = disabled_time; while (length--) { unsigned const src = dmaSrc++ & 0xFFFF; unsigned const data = (src & 0xE000) == 0x8000 || src > 0xFDFF ? 0xFF : read(src, cc); cc += 2 << doubleSpeed; if (cc - 3 > lOamDmaUpdate) { oamDmaPos_ = (oamDmaPos_ + 1) & 0xFF; lOamDmaUpdate += 4; if (oamDmaPos_ < 0xA0) { if (oamDmaPos_ == 0) startOamDma(lOamDmaUpdate - 1); ioamhram_[src & 0xFF] = data; } else if (oamDmaPos_ == 0xA0) { endOamDma(lOamDmaUpdate - 1); lOamDmaUpdate = disabled_time; } } nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cc); } lastOamDmaUpdate_ = lOamDmaUpdate; } cc += 4; dmaSource_ = dmaSrc; dmaDestination_ = dmaDest; ioamhram_[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram_[0x155] & 0x80); if ((ioamhram_[0x155] & 0x80) && lcd_.hdmaIsEnabled()) { if (lastOamDmaUpdate_ != disabled_time) updateOamDma(cc); lcd_.disableHdma(cc); } } break; case intevent_tima: tima_.doIrqEvent(TimaInterruptRequester(intreq_)); break; case intevent_video: lcd_.update(cc); break; case intevent_interrupts: if (halted()) { if (isCgb()) cc += 4; intreq_.unhalt(); intreq_.setEventTime<intevent_unhalt>(disabled_time); } if (ime()) { unsigned const pendingIrqs = intreq_.pendingIrqs(); unsigned const n = pendingIrqs & -pendingIrqs; unsigned address; if (n <= 4) { static unsigned char const lut[] = { 0x40, 0x48, 0x48, 0x50 }; address = lut[n-1]; } else address = 0x50 + n; intreq_.ackIrq(n); cc = interrupter_.interrupt(address, cc, *this); } break; } return cc; }
VertexBuffer::VertexBuffer() { updateSerial(); }
Buffer11::BufferStorage *Buffer11::getBufferStorage(BufferUsage usage) { BufferStorage *newStorage = NULL; auto directBufferIt = mBufferStorages.find(usage); if (directBufferIt != mBufferStorages.end()) { newStorage = directBufferIt->second; } if (!newStorage) { if (usage == BUFFER_USAGE_PIXEL_PACK) { newStorage = new PackStorage(mRenderer); } else if (usage == BUFFER_USAGE_SYSTEM_MEMORY) { newStorage = new SystemMemoryStorage(mRenderer); mHasSystemMemoryStorage = true; } else { // buffer is not allocated, create it newStorage = new NativeStorage(mRenderer, usage); } mBufferStorages.insert(std::make_pair(usage, newStorage)); } // resize buffer if (newStorage->getSize() < mSize) { if (newStorage->resize(mSize, true).isError()) { // Out of memory error return NULL; } } BufferStorage *latestBuffer = getLatestBufferStorage(); if (latestBuffer && latestBuffer->getDataRevision() > newStorage->getDataRevision()) { // Copy through a staging buffer if we're copying from or to a non-staging, mappable // buffer storage. This is because we can't map a GPU buffer, and copy CPU // data directly. If we're already using a staging buffer we're fine. if (latestBuffer->getUsage() != BUFFER_USAGE_STAGING && newStorage->getUsage() != BUFFER_USAGE_STAGING && (!latestBuffer->isMappable() || !newStorage->isMappable())) { NativeStorage *stagingBuffer = getStagingStorage(); stagingBuffer->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0); stagingBuffer->setDataRevision(latestBuffer->getDataRevision()); latestBuffer = stagingBuffer; } // if copyFromStorage returns true, the D3D buffer has been recreated // and we should update our serial if (newStorage->copyFromStorage(latestBuffer, 0, latestBuffer->getSize(), 0)) { updateSerial(); } newStorage->setDataRevision(latestBuffer->getDataRevision()); } return newStorage; }
void Memory::updateIrqs(const unsigned long cc) { updateSerial(cc); updateTimaIrq(cc); display.update(cc); }
void BufferStorage11::setData(const void* data, unsigned int size, unsigned int offset, GLenum bindingPoint) { ID3D11Device *device = mRenderer->getDevice(); ID3D11DeviceContext *context = mRenderer->getDeviceContext(); HRESULT result; unsigned int requiredBufferSize = size + offset; unsigned int requiredStagingSize = size; bool directInitialization = offset == 0 && (!mBuffer || mBufferSize < size + offset); if (!directInitialization) { if (!mStagingBuffer || mStagingBufferSize < requiredStagingSize) { if (mStagingBuffer) { mStagingBuffer->Release(); mStagingBuffer = NULL; mStagingBufferSize = 0; } D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = size; bufferDesc.Usage = D3D11_USAGE_STAGING; bufferDesc.BindFlags = 0; bufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; if (data) { D3D11_SUBRESOURCE_DATA initialData; initialData.pSysMem = data; initialData.SysMemPitch = size; initialData.SysMemSlicePitch = 0; result = device->CreateBuffer(&bufferDesc, &initialData, &mStagingBuffer); } else { result = device->CreateBuffer(&bufferDesc, NULL, &mStagingBuffer); } if (FAILED(result)) { return gl::error(GL_OUT_OF_MEMORY); } mStagingBufferSize = size; } else if (data) { D3D11_MAPPED_SUBRESOURCE mappedResource; result = context->Map(mStagingBuffer, 0, D3D11_MAP_WRITE, 0, &mappedResource); if (FAILED(result)) { return gl::error(GL_OUT_OF_MEMORY); } memcpy(mappedResource.pData, data, size); context->Unmap(mStagingBuffer, 0); } } if (!mBuffer || mBufferSize < size + offset) { D3D11_BUFFER_DESC bufferDesc; bufferDesc.ByteWidth = requiredBufferSize; bufferDesc.Usage = D3D11_USAGE_DEFAULT; if (mRenderer->getMajorShaderModel() > 2) bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER | D3D11_BIND_INDEX_BUFFER; else { if (bindingPoint == GL_ARRAY_BUFFER) bufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; else bufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; } bufferDesc.CPUAccessFlags = 0; bufferDesc.MiscFlags = 0; bufferDesc.StructureByteStride = 0; if (directInitialization) { // Since the data will fill the entire buffer (being larger than the initial size and having // no offset), the buffer can be initialized with the data so no staging buffer is required // No longer need the old buffer if (mBuffer) { mBuffer->Release(); mBuffer = NULL; mBufferSize = 0; } if (data) { D3D11_SUBRESOURCE_DATA initialData; initialData.pSysMem = data; initialData.SysMemPitch = size; initialData.SysMemSlicePitch = 0; result = device->CreateBuffer(&bufferDesc, &initialData, &mBuffer); } else { result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); } if (FAILED(result)) { return gl::error(GL_OUT_OF_MEMORY); } } else if (mBuffer && offset > 0) { // If offset is greater than zero and the buffer is non-null, need to preserve the data from // the old buffer up to offset ID3D11Buffer *newBuffer = NULL; result = device->CreateBuffer(&bufferDesc, NULL, &newBuffer); if (FAILED(result)) { return gl::error(GL_OUT_OF_MEMORY); } D3D11_BOX srcBox; srcBox.left = 0; srcBox.right = std::min(offset, mBufferSize); srcBox.top = 0; srcBox.bottom = 1; srcBox.front = 0; srcBox.back = 1; context->CopySubresourceRegion(newBuffer, 0, 0, 0, 0, mBuffer, 0, &srcBox); mBuffer->Release(); mBuffer = newBuffer; } else { // Simple case, nothing needs to be copied from the old buffer to the new one, just create // a new buffer // No longer need the old buffer if (mBuffer) { mBuffer->Release(); mBuffer = NULL; mBufferSize = 0; } // Create a new buffer for data storage result = device->CreateBuffer(&bufferDesc, NULL, &mBuffer); if (FAILED(result)) { return gl::error(GL_OUT_OF_MEMORY); } } updateSerial(); mBufferSize = bufferDesc.ByteWidth; } if (!directInitialization) { ASSERT(mStagingBuffer && mStagingBufferSize >= requiredStagingSize); // Data is already put into the staging buffer, copy it over to the data buffer D3D11_BOX srcBox; srcBox.left = 0; srcBox.right = size; srcBox.top = 0; srcBox.bottom = 1; srcBox.front = 0; srcBox.back = 1; context->CopySubresourceRegion(mBuffer, 0, offset, 0, 0, mStagingBuffer, 0, &srcBox); } mSize = std::max(mSize, offset + size); mWriteUsageCount = 0; mResolvedDataValid = false; }
IndexBuffer::IndexBuffer() { updateSerial(); }
unsigned long Memory::event(unsigned long cycleCounter) { if (lastOamDmaUpdate != DISABLED_TIME) updateOamDma(cycleCounter); switch (intreq.minEventId()) { case UNHALT: nontrivial_ff_write(0xFF04, 0, cycleCounter); PC = (PC + 1) & 0xFFFF; cycleCounter += 4; intreq.unhalt(); intreq.setEventTime<UNHALT>(DISABLED_TIME); break; case END: intreq.setEventTime<END>(DISABLED_TIME - 1); while (cycleCounter >= intreq.minEventTime() && intreq.eventTime(END) != DISABLED_TIME) cycleCounter = event(cycleCounter); intreq.setEventTime<END>(DISABLED_TIME); break; case BLIT: { const bool lcden = ioamhram[0x140] >> 7 & 1; unsigned long blitTime = intreq.eventTime(BLIT); if (lcden | blanklcd) { display.updateScreen(blanklcd, cycleCounter); intreq.setEventTime<BLIT>(DISABLED_TIME); intreq.setEventTime<END>(DISABLED_TIME); while (cycleCounter >= intreq.minEventTime()) cycleCounter = event(cycleCounter); } else blitTime += 70224 << isDoubleSpeed(); blanklcd = lcden ^ 1; intreq.setEventTime<BLIT>(blitTime); } break; case SERIAL: updateSerial(cycleCounter); break; case OAM: intreq.setEventTime<OAM>(lastOamDmaUpdate == DISABLED_TIME ? static_cast<unsigned long>(DISABLED_TIME) : intreq.eventTime(OAM) + 0xA0 * 4); break; case DMA: { const bool doubleSpeed = isDoubleSpeed(); unsigned dmaSrc = dmaSource; unsigned dmaDest = dmaDestination; unsigned dmaLength = ((ioamhram[0x155] & 0x7F) + 0x1) * 0x10; unsigned length = hdmaReqFlagged(intreq) ? 0x10 : dmaLength; ackDmaReq(&intreq); if ((static_cast<unsigned long>(dmaDest) + length) & 0x10000) { length = 0x10000 - dmaDest; ioamhram[0x155] |= 0x80; } dmaLength -= length; if (!(ioamhram[0x140] & 0x80)) dmaLength = 0; { unsigned long lOamDmaUpdate = lastOamDmaUpdate; lastOamDmaUpdate = DISABLED_TIME; while (length--) { const unsigned src = dmaSrc++ & 0xFFFF; const unsigned data = ((src & 0xE000) == 0x8000 || src > 0xFDFF) ? 0xFF : read(src, cycleCounter); cycleCounter += 2 << doubleSpeed; if (cycleCounter - 3 > lOamDmaUpdate) { oamDmaPos = (oamDmaPos + 1) & 0xFF; lOamDmaUpdate += 4; if (oamDmaPos < 0xA0) { if (oamDmaPos == 0) startOamDma(lOamDmaUpdate - 1); ioamhram[src & 0xFF] = data; } else if (oamDmaPos == 0xA0) { endOamDma(lOamDmaUpdate - 1); lOamDmaUpdate = DISABLED_TIME; } } nontrivial_write(0x8000 | (dmaDest++ & 0x1FFF), data, cycleCounter); } lastOamDmaUpdate = lOamDmaUpdate; } cycleCounter += 4; dmaSource = dmaSrc; dmaDestination = dmaDest; ioamhram[0x155] = ((dmaLength / 0x10 - 0x1) & 0xFF) | (ioamhram[0x155] & 0x80); if ((ioamhram[0x155] & 0x80) && display.hdmaIsEnabled()) { if (lastOamDmaUpdate != DISABLED_TIME) updateOamDma(cycleCounter); display.disableHdma(cycleCounter); } } break; case TIMA: tima.doIrqEvent(TimaInterruptRequester(intreq)); break; case VIDEO: display.update(cycleCounter); break; case INTERRUPTS: if (stopped) { intreq.setEventTime<INTERRUPTS>(DISABLED_TIME); break; } if (halted()) { if (gbIsCgb_ || (!gbIsCgb_ && cycleCounter <= halttime + 4)) cycleCounter += 4; intreq.unhalt(); intreq.setEventTime<UNHALT>(DISABLED_TIME); } if (ime()) { unsigned address; cycleCounter += 12; display.update(cycleCounter); SP = (SP - 2) & 0xFFFF; write(SP + 1, PC >> 8, cycleCounter); unsigned ie = intreq.iereg(); cycleCounter += 4; display.update(cycleCounter); write(SP, PC & 0xFF, cycleCounter); const unsigned pendingIrqs = ie & intreq.ifreg(); cycleCounter += 4; display.update(cycleCounter); const unsigned n = pendingIrqs & -pendingIrqs; if (n == 0) { address = 0; } else if (n < 8) { static const unsigned char lut[] = { 0x40, 0x48, 0x48, 0x50 }; address = lut[n-1]; } else address = 0x50 + n; intreq.ackIrq(n); PC = address; } break; } return cycleCounter; }