void buzzer_callback() { /* Start by incrementing the counter; we are playing the next note * This is here because the index must atually point to the note * currently playing, so main knows if we can go to LPM3 */ buzzer_counter++; /* Here the -1 is needed for the offset of buzzer_counter due to the * increment above. */ note n = *(buzzer_buffer + buzzer_counter - 1); /* 0x000F is the "stop bit" */ if(PITCH(n) == 0) { /* Stop buzzer */ buzzer_stop(); return; } if (PITCH(n) == 0x000F) { /* Stop the timer! We are playing a rest */ TA1CTL &= ~MC_3; } else { /* Set PWM frequency */ TA1CCR0 = base_notes[PITCH(n)] >> OCTAVE(n); /* Start the timer */ TA1CTL |= MC__UP; } /* Delay for DURATION(*n) milliseconds, */ timer0_delay_callback(DURATION(n), &buzzer_callback); }
void buzzer_play(note *notes) { /* Allow buzzer PWM output on P2.7 */ P2SEL |= BIT7; /* 0x000F is the "stop bit" */ while (PITCH(*notes) != 0x000F) { if (PITCH(*notes) == 0) { /* Stop the timer! We are playing a rest */ TA1CTL &= ~MC_3; } else { /* Set PWM frequency */ TA1CCR0 = base_notes[PITCH(*notes)] >> OCTAVE(*notes); /* Start the timer */ TA1CTL |= MC__UP; } /* Delay for DURATION(*notes) milliseconds, use LPM1 because we need SMCLK for tone generation */ timer0_delay(DURATION(*notes), LPM1_bits); /* Advance to the next note */ notes++; } /* Stop buzzer */ buzzer_stop(); }
void I_UpdateSoundParams(int channel, int vol, int sep, int pitch) { // proff 07/04/98: Added for CYGWIN32 compatibility #ifdef HAVE_LIBDSOUND int DSB_Status; if (noDSound == true) return; // proff 07/26/98: Added volume check if (vol==0) { IDirectSoundBuffer_Stop(lpSecondaryDSB[channel]); return; } IDirectSoundBuffer_SetVolume(lpSecondaryDSB[channel],VOL(vol)); IDirectSoundBuffer_SetPan(lpSecondaryDSB[channel],SEP(sep)); IDirectSoundBuffer_SetFrequency (lpSecondaryDSB[channel], ChannelInfo[channel].samplerate+PITCH(pitch)); if (ChannelInfo[channel].playing == true) { IDirectSoundBuffer_GetStatus(lpSecondaryDSB[channel], &DSB_Status); if ((DSB_Status & DSBSTATUS_PLAYING) == 0) IDirectSoundBuffer_Play(lpSecondaryDSB[channel], 0, 0, 0); } #endif // HAVE_LIBDSOUND }
void sna_read_boxes(struct sna *sna, PixmapPtr dst, struct kgem_bo *src_bo, const BoxRec *box, int nbox) { struct kgem *kgem = &sna->kgem; struct kgem_bo *dst_bo; BoxRec extents; const BoxRec *tmp_box; int tmp_nbox; void *ptr; int src_pitch, cpp, offset; int n, cmd, br13; bool can_blt; DBG(("%s x %d, src=(handle=%d), dst=(size=(%d, %d)\n", __FUNCTION__, nbox, src_bo->handle, dst->drawable.width, dst->drawable.height)); #ifndef NDEBUG for (n = 0; n < nbox; n++) { if (box[n].x1 < 0 || box[n].y1 < 0 || box[n].x2 * dst->drawable.bitsPerPixel/8 > src_bo->pitch || box[n].y2 * src_bo->pitch > kgem_bo_size(src_bo)) { FatalError("source out-of-bounds box[%d]=(%d, %d), (%d, %d), pitch=%d, size=%d\n", n, box[n].x1, box[n].y1, box[n].x2, box[n].y2, src_bo->pitch, kgem_bo_size(src_bo)); } } #endif /* XXX The gpu is faster to perform detiling in bulk, but takes * longer to setup and retrieve the results, with an additional * copy. The long term solution is to use snoopable bo and avoid * this path. */ if (download_inplace(kgem, dst, src_bo, box ,nbox)) { fallback: read_boxes_inplace(kgem, dst, src_bo, box, nbox); return; } can_blt = kgem_bo_can_blt(kgem, src_bo) && (box[0].x2 - box[0].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); extents = box[0]; for (n = 1; n < nbox; n++) { if (box[n].x1 < extents.x1) extents.x1 = box[n].x1; if (box[n].x2 > extents.x2) extents.x2 = box[n].x2; if (can_blt) can_blt = (box[n].x2 - box[n].x1) * dst->drawable.bitsPerPixel < 8 * (MAXSHORT - 4); if (box[n].y1 < extents.y1) extents.y1 = box[n].y1; if (box[n].y2 > extents.y2) extents.y2 = box[n].y2; } if (kgem_bo_can_map(kgem, src_bo)) { /* Is it worth detiling? */ if ((extents.y2 - extents.y1 - 1) * src_bo->pitch < 4096) goto fallback; } /* Try to avoid switching rings... */ if (!can_blt || kgem->ring == KGEM_RENDER || upload_too_large(sna, extents.x2 - extents.x1, extents.y2 - extents.y1)) { PixmapRec tmp; tmp.drawable.width = extents.x2 - extents.x1; tmp.drawable.height = extents.y2 - extents.y1; tmp.drawable.depth = dst->drawable.depth; tmp.drawable.bitsPerPixel = dst->drawable.bitsPerPixel; tmp.devPrivate.ptr = NULL; assert(tmp.drawable.width); assert(tmp.drawable.height); if (must_tile(sna, tmp.drawable.width, tmp.drawable.height)) { BoxRec tile, stack[64], *clipped, *c; int step; if (n > ARRAY_SIZE(stack)) { clipped = malloc(sizeof(BoxRec) * n); if (clipped == NULL) goto fallback; } else clipped = stack; step = MIN(sna->render.max_3d_size, 8*(MAXSHORT&~63) / dst->drawable.bitsPerPixel); while (step * step * 4 > sna->kgem.max_upload_tile_size) step /= 2; DBG(("%s: tiling download, using %dx%d tiles\n", __FUNCTION__, step, step)); assert(step); for (tile.y1 = extents.y1; tile.y1 < extents.y2; tile.y1 = tile.y2) { int y2 = tile.y1 + step; if (y2 > extents.y2) y2 = extents.y2; tile.y2 = y2; for (tile.x1 = extents.x1; tile.x1 < extents.x2; tile.x1 = tile.x2) { int x2 = tile.x1 + step; if (x2 > extents.x2) x2 = extents.x2; tile.x2 = x2; tmp.drawable.width = tile.x2 - tile.x1; tmp.drawable.height = tile.y2 - tile.y1; c = clipped; for (n = 0; n < nbox; n++) { *c = box[n]; if (!box_intersect(c, &tile)) continue; DBG(("%s: box(%d, %d), (%d, %d),, dst=(%d, %d)\n", __FUNCTION__, c->x1, c->y1, c->x2, c->y2, c->x1 - tile.x1, c->y1 - tile.y1)); c++; } if (c == clipped) continue; dst_bo = kgem_create_buffer_2d(kgem, tmp.drawable.width, tmp.drawable.height, tmp.drawable.bitsPerPixel, KGEM_BUFFER_LAST, &ptr); if (!dst_bo) { if (clipped != stack) free(clipped); goto fallback; } if (!sna->render.copy_boxes(sna, GXcopy, dst, src_bo, 0, 0, &tmp, dst_bo, -tile.x1, -tile.y1, clipped, c-clipped, COPY_LAST)) { kgem_bo_destroy(&sna->kgem, dst_bo); if (clipped != stack) free(clipped); goto fallback; } kgem_bo_submit(&sna->kgem, dst_bo); kgem_buffer_read_sync(kgem, dst_bo); if (sigtrap_get() == 0) { while (c-- != clipped) { memcpy_blt(ptr, dst->devPrivate.ptr, tmp.drawable.bitsPerPixel, dst_bo->pitch, dst->devKind, c->x1 - tile.x1, c->y1 - tile.y1, c->x1, c->y1, c->x2 - c->x1, c->y2 - c->y1); } sigtrap_put(); } kgem_bo_destroy(&sna->kgem, dst_bo); } } if (clipped != stack) free(clipped); } else { dst_bo = kgem_create_buffer_2d(kgem, tmp.drawable.width, tmp.drawable.height, tmp.drawable.bitsPerPixel, KGEM_BUFFER_LAST, &ptr); if (!dst_bo) goto fallback; if (!sna->render.copy_boxes(sna, GXcopy, dst, src_bo, 0, 0, &tmp, dst_bo, -extents.x1, -extents.y1, box, nbox, COPY_LAST)) { kgem_bo_destroy(&sna->kgem, dst_bo); goto fallback; } kgem_bo_submit(&sna->kgem, dst_bo); kgem_buffer_read_sync(kgem, dst_bo); if (sigtrap_get() == 0) { for (n = 0; n < nbox; n++) { memcpy_blt(ptr, dst->devPrivate.ptr, tmp.drawable.bitsPerPixel, dst_bo->pitch, dst->devKind, box[n].x1 - extents.x1, box[n].y1 - extents.y1, box[n].x1, box[n].y1, box[n].x2 - box[n].x1, box[n].y2 - box[n].y1); } sigtrap_put(); } kgem_bo_destroy(&sna->kgem, dst_bo); } return; } /* count the total number of bytes to be read and allocate a bo */ cpp = dst->drawable.bitsPerPixel / 8; offset = 0; for (n = 0; n < nbox; n++) { int height = box[n].y2 - box[n].y1; int width = box[n].x2 - box[n].x1; offset += PITCH(width, cpp) * height; } DBG((" read buffer size=%d\n", offset)); dst_bo = kgem_create_buffer(kgem, offset, KGEM_BUFFER_LAST, &ptr); if (!dst_bo) { read_boxes_inplace(kgem, dst, src_bo, box, nbox); return; } cmd = XY_SRC_COPY_BLT_CMD; src_pitch = src_bo->pitch; if (kgem->gen >= 040 && src_bo->tiling) { cmd |= BLT_SRC_TILED; src_pitch >>= 2; }
int I_StartSound(sfxinfo_t *sound, int vol, int sep, int pitch, int pri) { int channel=0; // proff 07/04/98: Added for CYGWIN32 compatibility #ifdef HAVE_LIBDSOUND HRESULT error; char *snddata; int sndlength; if (noDSound == true) return channel; // load sound data if we have not already I_CacheSound(sound); // find a free channel channel = I_GetFreeChannel(); // proff 07/26/98: Added volume check // proff 10/31/98: Added Stop before updating sound-data error = IDirectSoundBuffer_Stop(lpSecondaryDSB[channel]); ChannelInfo[channel].playing = false; if (vol==0) return channel; snddata = sound->data; ChannelInfo[channel].samplerate = (snddata[3] << 8) + snddata[2]; // proff 10/31/98: Use accurate time for this one ChannelInfo[channel].endtime = I_GetTime_RealTime() + (sound->length * 35) / ChannelInfo[channel].samplerate + 1; // skip past header snddata += 8; sndlength = sound->length - 8; error = IDirectSoundBuffer_SetCurrentPosition(lpSecondaryDSB[channel],0); // proff 11/09/98: Added for a slight speedup if (sound != ChannelInfo[channel].sfx) { DWORD *hand1,*hand2; DWORD len1,len2; ChannelInfo[channel].sfx = sound; error = IDirectSoundBuffer_Lock(lpSecondaryDSB[channel],0,65535, &hand1,&len1,&hand2,&len2, DSBLOCK_FROMWRITECURSOR); if (len1 >= sndlength) { memset(hand1, 128, len1); memcpy(hand1, snddata , sndlength); memset(hand2, 128, len2); } else { memcpy(hand1, snddata, len1); memcpy(hand2, &((char *)snddata)[len1], sndlength-len1); } error = IDirectSoundBuffer_Unlock (lpSecondaryDSB[channel], hand1, len1, hand2, len2); } IDirectSoundBuffer_SetVolume(lpSecondaryDSB[channel], VOL(vol)); IDirectSoundBuffer_SetPan(lpSecondaryDSB[channel], SEP(sep)); IDirectSoundBuffer_SetFrequency(lpSecondaryDSB[channel], ChannelInfo[channel].samplerate+PITCH(pitch)); error = IDirectSoundBuffer_Play(lpSecondaryDSB[channel], 0, 0, 0); ChannelInfo[channel].playing = true; #endif // HAVE_LIBDSOUND return channel; }
bool GLDriver::checkActiveTextures() { std::vector<uint8_t> untiledImage, untiledMipmap; gx2::GX2Surface surface; for (auto i = 0; i < latte::MaxTextures; ++i) { auto resourceOffset = (latte::SQ_PS_TEX_RESOURCE_0 + i) * 7; auto sq_tex_resource_word0 = getRegister<latte::SQ_TEX_RESOURCE_WORD0_N>(latte::Register::SQ_TEX_RESOURCE_WORD0_0 + 4 * resourceOffset); auto sq_tex_resource_word1 = getRegister<latte::SQ_TEX_RESOURCE_WORD1_N>(latte::Register::SQ_TEX_RESOURCE_WORD1_0 + 4 * resourceOffset); auto sq_tex_resource_word2 = getRegister<latte::SQ_TEX_RESOURCE_WORD2_N>(latte::Register::SQ_TEX_RESOURCE_WORD2_0 + 4 * resourceOffset); auto sq_tex_resource_word3 = getRegister<latte::SQ_TEX_RESOURCE_WORD3_N>(latte::Register::SQ_TEX_RESOURCE_WORD3_0 + 4 * resourceOffset); auto sq_tex_resource_word4 = getRegister<latte::SQ_TEX_RESOURCE_WORD4_N>(latte::Register::SQ_TEX_RESOURCE_WORD4_0 + 4 * resourceOffset); auto sq_tex_resource_word5 = getRegister<latte::SQ_TEX_RESOURCE_WORD5_N>(latte::Register::SQ_TEX_RESOURCE_WORD5_0 + 4 * resourceOffset); auto sq_tex_resource_word6 = getRegister<latte::SQ_TEX_RESOURCE_WORD6_N>(latte::Register::SQ_TEX_RESOURCE_WORD6_0 + 4 * resourceOffset); auto baseAddress = sq_tex_resource_word2.BASE_ADDRESS() << 8; if (!baseAddress) { continue; } if (baseAddress == mPixelTextureCache[i].baseAddress && sq_tex_resource_word0.value == mPixelTextureCache[i].word0 && sq_tex_resource_word1.value == mPixelTextureCache[i].word1 && sq_tex_resource_word2.value == mPixelTextureCache[i].word2 && sq_tex_resource_word3.value == mPixelTextureCache[i].word3 && sq_tex_resource_word4.value == mPixelTextureCache[i].word4 && sq_tex_resource_word5.value == mPixelTextureCache[i].word5 && sq_tex_resource_word6.value == mPixelTextureCache[i].word6) { continue; // No change in sampler state } mPixelTextureCache[i].baseAddress = baseAddress; mPixelTextureCache[i].word0 = sq_tex_resource_word0.value; mPixelTextureCache[i].word1 = sq_tex_resource_word1.value; mPixelTextureCache[i].word2 = sq_tex_resource_word2.value; mPixelTextureCache[i].word3 = sq_tex_resource_word3.value; mPixelTextureCache[i].word4 = sq_tex_resource_word4.value; mPixelTextureCache[i].word5 = sq_tex_resource_word5.value; mPixelTextureCache[i].word6 = sq_tex_resource_word6.value; // Decode resource registers auto pitch = (sq_tex_resource_word0.PITCH() + 1) * 8; auto width = sq_tex_resource_word0.TEX_WIDTH() + 1; auto height = sq_tex_resource_word1.TEX_HEIGHT() + 1; auto depth = sq_tex_resource_word1.TEX_DEPTH() + 1; auto format = sq_tex_resource_word1.DATA_FORMAT(); auto tileMode = sq_tex_resource_word0.TILE_MODE(); auto numFormat = sq_tex_resource_word4.NUM_FORMAT_ALL(); auto formatComp = sq_tex_resource_word4.FORMAT_COMP_X(); auto degamma = sq_tex_resource_word4.FORCE_DEGAMMA(); auto dim = sq_tex_resource_word0.DIM(); auto buffer = getSurfaceBuffer(baseAddress, width, height, depth, dim, format, numFormat, formatComp, degamma, sq_tex_resource_word0.TILE_TYPE()); if (buffer->dirtyAsTexture) { auto swizzle = sq_tex_resource_word2.SWIZZLE() << 8; // Rebuild a GX2Surface std::memset(&surface, 0, sizeof(gx2::GX2Surface)); surface.dim = static_cast<gx2::GX2SurfaceDim>(dim); surface.width = width; surface.height = height; if (surface.dim == gx2::GX2SurfaceDim::TextureCube) { surface.depth = depth * 6; } else if (surface.dim == gx2::GX2SurfaceDim::Texture3D || surface.dim == gx2::GX2SurfaceDim::Texture2DMSAAArray || surface.dim == gx2::GX2SurfaceDim::Texture2DArray || surface.dim == gx2::GX2SurfaceDim::Texture1DArray) { surface.depth = depth; } else { surface.depth = 1; } surface.mipLevels = 1; surface.format = getSurfaceFormat(format, numFormat, formatComp, degamma); surface.aa = gx2::GX2AAMode::Mode1X; surface.use = gx2::GX2SurfaceUse::Texture; if (sq_tex_resource_word0.TILE_TYPE()) { surface.use |= gx2::GX2SurfaceUse::DepthBuffer; } surface.tileMode = static_cast<gx2::GX2TileMode>(tileMode); surface.swizzle = swizzle; // Update the sizing information for the surface GX2CalcSurfaceSizeAndAlignment(&surface); // Align address baseAddress &= ~(surface.alignment - 1); surface.image = make_virtual_ptr<uint8_t>(baseAddress); surface.mipmaps = nullptr; // Calculate a new memory CRC uint64_t newHash[2] = { 0 }; MurmurHash3_x64_128(surface.image, surface.imageSize, 0, newHash); // If the CPU memory has changed, we should re-upload this. This hashing is // also means that if the application temporarily uses one of its buffers as // a color buffer, we are able to accurately handle this. Providing they are // not updating the memory at the same time. if (newHash[0] != buffer->cpuMemHash[0] || newHash[1] != buffer->cpuMemHash[1]) { buffer->cpuMemHash[0] = newHash[0]; buffer->cpuMemHash[1] = newHash[1]; // Untile gx2::internal::convertTiling(&surface, untiledImage, untiledMipmap); // Create texture auto compressed = isCompressedFormat(format); auto target = getTextureTarget(dim); auto textureDataType = gl::GL_INVALID_ENUM; auto textureFormat = getTextureFormat(format); auto size = untiledImage.size(); if (compressed) { textureDataType = getCompressedTextureDataType(format, degamma); } else { textureDataType = getTextureDataType(format, formatComp); } if (textureDataType == gl::GL_INVALID_ENUM || textureFormat == gl::GL_INVALID_ENUM) { decaf_abort(fmt::format("Texture with unsupported format {}", surface.format.value())); } switch (dim) { case latte::SQ_TEX_DIM_1D: if (compressed) { gl::glCompressedTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage1D(buffer->object, 0, /* level */ 0, /* xoffset */ width, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_2D: if (compressed) { gl::glCompressedTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage2D(buffer->object, 0, /* level */ 0, 0, /* xoffset, yoffset */ width, height, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_3D: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, depth, textureFormat, textureDataType, untiledImage.data()); } break; case latte::SQ_TEX_DIM_CUBEMAP: decaf_check(surface.depth == 6); case latte::SQ_TEX_DIM_2D_ARRAY: if (compressed) { gl::glCompressedTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureDataType, gsl::narrow_cast<gl::GLsizei>(size), untiledImage.data()); } else { gl::glTextureSubImage3D(buffer->object, 0, /* level */ 0, 0, 0, /* xoffset, yoffset, zoffset */ width, height, surface.depth, textureFormat, textureDataType, untiledImage.data()); } break; default: decaf_abort(fmt::format("Unsupported texture dim: {}", sq_tex_resource_word0.DIM())); } } buffer->dirtyAsTexture = false; buffer->state = SurfaceUseState::CpuWritten; } // Setup texture swizzle auto dst_sel_x = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_X()); auto dst_sel_y = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Y()); auto dst_sel_z = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_Z()); auto dst_sel_w = getTextureSwizzle(sq_tex_resource_word4.DST_SEL_W()); gl::GLint textureSwizzle[] = { static_cast<gl::GLint>(dst_sel_x), static_cast<gl::GLint>(dst_sel_y), static_cast<gl::GLint>(dst_sel_z), static_cast<gl::GLint>(dst_sel_w), }; gl::glTextureParameteriv(buffer->object, gl::GL_TEXTURE_SWIZZLE_RGBA, textureSwizzle); gl::glBindTextureUnit(i, buffer->object); } return true; }